first go at redoing the tracker inspector tab (some functionality is still missing)

This commit is contained in:
Mitchell Livingston 2009-09-28 01:57:35 +00:00
parent 8bfdf85ac3
commit a9101bb1c2
9 changed files with 377 additions and 83 deletions

View File

@ -80,6 +80,7 @@
A215BF5C0F02EBB800350CDB /* GroupRules.xib in Resources */ = {isa = PBXBuildFile; fileRef = A215BF5B0F02EBB800350CDB /* GroupRules.xib */; };
A219798B0D07B78400438EA7 /* GroupToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = A219798A0D07B78400438EA7 /* GroupToolbarItem.m */; };
A21A9BE2106D86A800F1C3C1 /* TrackerNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A21A9BE1106D86A800F1C3C1 /* TrackerNode.m */; };
A21A9D41106EC2E800F1C3C1 /* TrackerCell.m in Sources */ = {isa = PBXBuildFile; fileRef = A21A9D40106EC2E800F1C3C1 /* TrackerCell.m */; };
A21DFF100A292B2B007C5F76 /* Transfers.png in Resources */ = {isa = PBXBuildFile; fileRef = A21DFF0F0A292B2B007C5F76 /* Transfers.png */; };
A21FBBAB0EDA78C300BC3C51 /* bandwidth.h in Headers */ = {isa = PBXBuildFile; fileRef = A21FBBA90EDA78C300BC3C51 /* bandwidth.h */; };
A21FBBAC0EDA78C300BC3C51 /* bandwidth.c in Sources */ = {isa = PBXBuildFile; fileRef = A21FBBAA0EDA78C300BC3C51 /* bandwidth.c */; };
@ -489,6 +490,8 @@
A219798A0D07B78400438EA7 /* GroupToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = GroupToolbarItem.m; path = macosx/GroupToolbarItem.m; sourceTree = "<group>"; };
A21A9BE0106D86A800F1C3C1 /* TrackerNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrackerNode.h; path = macosx/TrackerNode.h; sourceTree = "<group>"; };
A21A9BE1106D86A800F1C3C1 /* TrackerNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TrackerNode.m; path = macosx/TrackerNode.m; sourceTree = "<group>"; };
A21A9D3F106EC2E800F1C3C1 /* TrackerCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = TrackerCell.h; path = macosx/TrackerCell.h; sourceTree = "<group>"; };
A21A9D40106EC2E800F1C3C1 /* TrackerCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = TrackerCell.m; path = macosx/TrackerCell.m; sourceTree = "<group>"; };
A21DFF0F0A292B2B007C5F76 /* Transfers.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = Transfers.png; path = macosx/Images/Transfers.png; sourceTree = "<group>"; };
A21FBBA90EDA78C300BC3C51 /* bandwidth.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = bandwidth.h; path = libtransmission/bandwidth.h; sourceTree = "<group>"; };
A21FBBAA0EDA78C300BC3C51 /* bandwidth.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = bandwidth.c; path = libtransmission/bandwidth.c; sourceTree = "<group>"; };
@ -1381,6 +1384,8 @@
A2AA579B0ADFCAB400CA59F6 /* PiecesView.m */,
A2725D5B0DE7507C003445E7 /* TrackerTableView.h */,
A2725D5C0DE7507C003445E7 /* TrackerTableView.m */,
A21A9D3F106EC2E800F1C3C1 /* TrackerCell.h */,
A21A9D40106EC2E800F1C3C1 /* TrackerCell.m */,
);
name = "Info Window";
sourceTree = "<group>";
@ -1996,6 +2001,7 @@
A23F526F0F14395900AA02E3 /* PredicateEditorRowTemplateAny.m in Sources */,
A29D84041049C25600D1987A /* NSApplicationAdditions.m in Sources */,
A21A9BE2106D86A800F1C3C1 /* TrackerNode.m in Sources */,
A21A9D41106EC2E800F1C3C1 /* TrackerCell.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@ -29,7 +29,6 @@
#import "Controller.h"
#import "Torrent.h"
#import "TorrentGroup.h"
#import "TorrentCell.h"
#import "TorrentTableView.h"
#import "CreatorWindowController.h"
#import "StatsWindowController.h"

View File

@ -28,6 +28,7 @@
@class Torrent;
@class TrackerTableView;
@class TrackerCell;
@class FileOutlineController;
@class PiecesView;
@ -53,6 +54,7 @@
IBOutlet NSButton * fRevealDataButton;
IBOutlet TrackerTableView * fTrackerTable;
TrackerCell * fTrackerCell;
IBOutlet NSSegmentedControl * fTrackerAddRemoveControl;
NSArray * fPeers, * fWebSeeds;

View File

@ -32,6 +32,7 @@
#import "PeerProgressIndicatorCell.h"
#import "PiecesView.h"
#import "Torrent.h"
#import "TrackerCell.h"
#import "TrackerNode.h"
#import "TrackerTableView.h"
#include "utils.h" //tr_getRatio()
@ -45,6 +46,8 @@
#define TAB_MIN_HEIGHT 250
#define TRACKER_GROUP_SEPARATOR_HEIGHT 14.0
#define PIECES_CONTROL_PROGRESS 0
#define PIECES_CONTROL_AVAILABLE 1
@ -96,7 +99,12 @@ typedef enum
- (id) init
{
return [super initWithWindowNibName: @"InfoWindow"];
if ((self = [super initWithWindowNibName: @"InfoWindow"]))
{
fTrackerCell = [[TrackerCell alloc] init];
}
return self;
}
- (void) awakeFromNib
@ -236,6 +244,8 @@ typedef enum
[fWebSeedTableAnimation release];
[fTrackerCell release];
[fTrackerIconCache release];
[fTrackerIconCacheLeopard release];
[fTrackerIconLoading release];
@ -890,10 +900,11 @@ typedef enum
}
else if (tableView == fTrackerTable)
{
NSString * ident = [column identifier];
//NSString * ident = [column identifier];
id item = [fTrackers objectAtIndex: row];
if ([ident isEqualToString: @"Icon"])
#warning isn't used
/*if ([ident isEqualToString: @"Icon"])
{
NSAssert([item isKindOfClass: [TrackerNode class]], @"Value passed to tracker table's icon row is not a TrackerNode!");
@ -917,11 +928,13 @@ typedef enum
}
return (icon && icon != [NSNull null]) ? icon : [NSImage imageNamed: @"FavIcon.png"];
}
if ([ident isEqualToString: @"Address"])
return [(TrackerNode *)item host];
else
}*/
if ([item isKindOfClass: [NSNumber class]])
return [NSString stringWithFormat: NSLocalizedString(@"Tier %d", "Inspector -> tracker table"), [item integerValue]];
else
return item;
}
return nil;
}
@ -954,18 +967,28 @@ typedef enum
[pool drain];
}
- (NSCell *)tableView: (NSTableView *) tableView dataCellForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
- (NSCell *) tableView: (NSTableView *) tableView dataCellForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
{
if (tableView == fTrackerTable)
{
//group row the full column width
if (!tableColumn && [[fTrackers objectAtIndex: row] isKindOfClass: [NSNumber class]])
return [[tableView tableColumnWithIdentifier: @"Address"] dataCell];
const BOOL group = [[fTrackers objectAtIndex: row] isKindOfClass: [NSNumber class]];
return group ? [tableColumn dataCellForRow: row] : fTrackerCell;
}
return nil;
}
- (CGFloat) tableView: (NSTableView *) tableView heightOfRow: (NSInteger) row
{
if (tableView == fTrackerTable)
{
if ([[fTrackers objectAtIndex: row] isKindOfClass: [NSNumber class]])
return TRACKER_GROUP_SEPARATOR_HEIGHT;
}
return [tableView rowHeight];
}
- (void) tableView: (NSTableView *) tableView willDisplayCell: (id) cell forTableColumn: (NSTableColumn *) tableColumn
row: (NSInteger) row
{
@ -1731,7 +1754,7 @@ typedef enum
[fTrackerTable reloadData];
[fTrackerTable selectRowIndexes: [NSIndexSet indexSetWithIndex: [fTrackers count]-1] byExtendingSelection: NO];
[fTrackerTable editColumn: [fTrackerTable columnWithIdentifier: @"Address"] row: [fTrackers count]-1 withEvent: nil select: YES];
[fTrackerTable editColumn: [fTrackerTable columnWithIdentifier: @"Tracker"] row: [fTrackers count]-1 withEvent: nil select: YES];
}
- (void) removeTrackers

32
macosx/TrackerCell.h Normal file
View File

@ -0,0 +1,32 @@
/******************************************************************************
* $Id$
*
* Copyright (c) 2009 Transmission authors and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#import <Cocoa/Cocoa.h>
@interface TrackerCell : NSActionCell
{
NSMutableDictionary * fNameAttributes, * fStatusAttributes;
}
@end

192
macosx/TrackerCell.m Normal file
View File

@ -0,0 +1,192 @@
/******************************************************************************
* $Id$
*
* Copyright (c) 2009 Transmission authors and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#import "TrackerCell.h"
#import "TrackerNode.h"
#define PADDING_HORIZONAL 2.0
#define PADDING_STATUS_HORIZONAL 4.0
#define ICON_SIZE 14.0
#define PADDING_BETWEEN_IMAGE_AND_NAME 4.0
#define PADDING_ABOVE_NAME 2.0
#define PADDING_BETWEEN_LINES 1.0
@interface TrackerCell (Private)
- (NSImage *) favIcon;
- (NSRect) imageRectForBounds: (NSRect) bounds;
- (NSRect) rectForNameWithString: (NSAttributedString *) string inBounds: (NSRect) bounds;
- (NSRect) rectForStatusWithString: (NSAttributedString *) string withAboveRect: (NSRect) nameRect inBounds: (NSRect) bounds;
- (NSAttributedString *) attributedNameWithColor: (NSColor *) color;
- (NSAttributedString *) attributedStatusWithString: (NSString *) statusString color: (NSColor *) color;
@end
@implementation TrackerCell
- (id) init
{
if ((self = [super init]))
{
NSMutableParagraphStyle * paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[paragraphStyle setLineBreakMode: NSLineBreakByTruncatingTail];
fNameAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSFont messageFontOfSize: 11.0], NSFontAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
fStatusAttributes = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
[NSFont messageFontOfSize: 9.0], NSFontAttributeName,
paragraphStyle, NSParagraphStyleAttributeName, nil];
[paragraphStyle release];
}
return self;
}
- (void) dealloc
{
[fNameAttributes release];
[fStatusAttributes release];
[super dealloc];
}
- (id) copyWithZone: (NSZone *) zone
{
TrackerCell * copy = [super copyWithZone: zone];
copy->fNameAttributes = [fNameAttributes retain];
copy->fStatusAttributes = [fStatusAttributes retain];
return copy;
}
- (void) drawWithFrame: (NSRect) cellFrame inView: (NSView *) controlView
{
//icon
[[self favIcon] drawInRect: [self imageRectForBounds: cellFrame] fromRect: NSZeroRect operation: NSCompositeSourceOver
fraction: 1.0];
NSColor * nameColor, * statusColor;
if ([self backgroundStyle] == NSBackgroundStyleDark)
nameColor = statusColor = [NSColor whiteColor];
else
{
nameColor = [NSColor controlTextColor];
statusColor = [NSColor darkGrayColor];
}
//name
NSAttributedString * nameString = [self attributedNameWithColor: nameColor];
NSRect nameRect = [self rectForNameWithString: nameString inBounds: cellFrame];
[nameString drawInRect: nameRect];
//status strings
TrackerNode * node = (TrackerNode *)[self objectValue];
NSAttributedString * lastAnnounceString = [self attributedStatusWithString: [node lastAnnounceStatusString] color: statusColor];
NSRect lastAnnounceRect = [self rectForStatusWithString: lastAnnounceString withAboveRect: nameRect inBounds: cellFrame];
[lastAnnounceString drawInRect: lastAnnounceRect];
NSAttributedString * nextAnnounceString = [self attributedStatusWithString: [node nextAnnounceStatusString] color: statusColor];
NSRect nextAnnounceRect = [self rectForStatusWithString: nextAnnounceString withAboveRect: lastAnnounceRect inBounds: cellFrame];
[nextAnnounceString drawInRect: nextAnnounceRect];
NSAttributedString * lastScrapeString = [self attributedStatusWithString: [node lastScrapeStatusString] color: statusColor];
NSRect lastScrapeRect = [self rectForStatusWithString: lastScrapeString withAboveRect: nextAnnounceRect inBounds: cellFrame];
[lastScrapeString drawInRect: lastScrapeRect];
NSLog(@"%f", NSMaxY(lastScrapeRect)-NSMinY(cellFrame));
}
@end
@implementation TrackerCell (Private)
#warning needed?
- (NSImage *) favIcon
{
return [NSImage imageNamed: @"FavIcon.png"];
}
- (NSRect) imageRectForBounds: (NSRect) bounds
{
NSRect result = bounds;
result.origin.x += PADDING_HORIZONAL;
result.origin.y += PADDING_ABOVE_NAME;
result.size = NSMakeSize(ICON_SIZE, ICON_SIZE);
return result;
}
- (NSRect) rectForNameWithString: (NSAttributedString *) string inBounds: (NSRect) bounds
{
const NSSize nameSize = [string size];
NSRect result = bounds;
result.origin.x += PADDING_HORIZONAL + ICON_SIZE + PADDING_BETWEEN_IMAGE_AND_NAME;
result.origin.y += PADDING_ABOVE_NAME;
result.size = nameSize;
result.size.width = MIN(result.size.width, NSMaxX(bounds) - NSMinX(result));
return result;
}
- (NSRect) rectForStatusWithString: (NSAttributedString *) string withAboveRect: (NSRect) nameRect inBounds: (NSRect) bounds;
{
const NSSize statusSize = [string size];
NSRect result = bounds;
result.origin.x += PADDING_STATUS_HORIZONAL;
result.origin.y = NSMaxY(nameRect) + PADDING_BETWEEN_LINES;
result.size = statusSize;
result.size.width = MIN(result.size.width, NSMaxX(bounds) - NSMinX(result));
return result;
}
- (NSAttributedString *) attributedNameWithColor: (NSColor *) color
{
if (color)
[fNameAttributes setObject: color forKey: NSForegroundColorAttributeName];
NSString * name = [(TrackerNode *)[self objectValue] host];
return [[[NSAttributedString alloc] initWithString: name attributes: fNameAttributes] autorelease];
}
- (NSAttributedString *) attributedStatusWithString: (NSString *) statusString color: (NSColor *) color
{
if (color)
[fStatusAttributes setObject: color forKey: NSForegroundColorAttributeName];
return [[[NSAttributedString alloc] initWithString: statusString attributes: fStatusAttributes] autorelease];
}
@end

View File

@ -34,6 +34,10 @@
- (NSString *) host;
- (NSString *) lastAnnounceStatusString;
- (NSString *) nextAnnounceStatusString;
- (NSString *) lastScrapeStatusString;
#if 0
- (BOOL) isActive;
@ -51,6 +55,7 @@
- (int) lastAnnouncePeerCount;
- (NSString *) lastAnnounceResult;
- (NSDate *) lastAnnounceDate;
- (NSDate *) lastAnnounceStartDate;
- (BOOL) lastAnnounceSucceeded;
- (NSDate *) lastAnnounceDate;

View File

@ -23,6 +23,8 @@
*****************************************************************************/
#import "TrackerNode.h"
#import "NSApplicationAdditions.h"
#import "NSStringAdditions.h"
@implementation TrackerNode
@ -36,9 +38,90 @@
return self;
}
- (id) copyWithZone: (NSZone *) zone
{
//this object is essentially immutable after initial setup
return [self retain];
}
- (NSString *) host
{
return [NSString stringWithUTF8String: fStat.host];
}
#warning work in peer count?
#warning consider "isActive"
- (NSString *) lastAnnounceStatusString
{
NSString * dateString;
if (fStat.hasAnnounced && fStat.lastAnnounceTime != 0)
{
NSDate * announceDate = [NSDate dateWithTimeIntervalSince1970: fStat.lastAnnounceTime];
if ([NSApp isOnSnowLeopardOrBetter])
dateString = [NSDateFormatter localizedStringFromDate: announceDate dateStyle: NSDateFormatterFullStyle
timeStyle: NSDateFormatterShortStyle];
else
{
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle: NSDateFormatterFullStyle];
[dateFormatter setTimeStyle: NSDateFormatterShortStyle];
dateString = [dateFormatter stringFromDate: announceDate];
[dateFormatter release];
}
}
else
dateString = NSLocalizedString(@"N/A", "Tracker last announce");
if (fStat.hasAnnounced && !fStat.lastAnnounceSucceeded)
dateString = [NSString stringWithFormat: @"%@: %@ - %@", NSLocalizedString(@"Announce error", "Tracker last announce"),
[NSString stringWithUTF8String: fStat.lastAnnounceResult], dateString];
else
dateString = [NSString stringWithFormat: NSLocalizedString(@"Last Announce: %@", "Tracker last announce"), dateString];
return dateString;
}
- (NSString *) nextAnnounceStatusString
{
if (fStat.isAnnouncing)
return [NSLocalizedString(@"Announce in progress", "Tracker next announce") stringByAppendingEllipsis];
else if (fStat.willAnnounce)
return [NSString stringWithFormat: NSLocalizedString(@"Next announce in %@", "Tracker next announce"),
[NSString timeString: fStat.nextAnnounceTime - [[NSDate date] timeIntervalSince1970] showSeconds: YES]];
else
return NSLocalizedString(@"Announce not scheduled", "Tracker next announce");
}
- (NSString *) lastScrapeStatusString
{
NSString * dateString;
if (fStat.hasScraped && fStat.lastScrapeTime != 0)
{
NSDate * scrapeDate = [NSDate dateWithTimeIntervalSince1970: fStat.lastScrapeTime];
if ([NSApp isOnSnowLeopardOrBetter])
dateString = [NSDateFormatter localizedStringFromDate: scrapeDate dateStyle: NSDateFormatterFullStyle
timeStyle: NSDateFormatterShortStyle];
else
{
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateStyle: NSDateFormatterFullStyle];
[dateFormatter setTimeStyle: NSDateFormatterShortStyle];
dateString = [dateFormatter stringFromDate: scrapeDate];
[dateFormatter release];
}
}
else
dateString = NSLocalizedString(@"N/A", "Tracker last announce");
if (fStat.hasScraped && !fStat.lastScrapeSucceeded)
dateString = [NSString stringWithFormat: @"%@: %@ - %@", NSLocalizedString(@"Scrape error", "Tracker last announce"),
[NSString stringWithUTF8String: fStat.lastScrapeResult], dateString];
else
dateString = [NSString stringWithFormat: NSLocalizedString(@"Last Scrape: %@", "Tracker last announce"), dateString];
return dateString;
}
@end

View File

@ -12,8 +12,7 @@
</object>
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
<bool key="EncodedWithXMLCoder">YES</bool>
<integer value="995"/>
<integer value="965"/>
<integer value="1731"/>
</object>
<object class="NSArray" key="IBDocument.PluginDependencies">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -423,7 +422,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
</object>
<object class="NSCustomView" id="179482273">
<reference key="NSNextResponder"/>
<nil key="NSNextResponder"/>
<int key="NSvFlags">258</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -836,7 +835,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<nil key="NSDefaultParagraphStyle"/>
</object>
<int key="NSTVFlags">6</int>
<string key="NSMaxSize">{503, 1e+07}</string>
<string key="NSMaxSize">{509, 1e+07}</string>
<string key="NSMinize">{87, 0}</string>
<nil key="NSDelegate"/>
</object>
@ -884,14 +883,13 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
</object>
</object>
<string key="NSFrameSize">{350, 210}</string>
<reference key="NSSuperview"/>
<object class="NSMutableString" key="NSClassName">
<characters key="NS.bytes">NSView</characters>
</object>
<string key="NSExtension">NSResponder</string>
</object>
<object class="NSCustomView" id="717510682">
<reference key="NSNextResponder"/>
<nil key="NSNextResponder"/>
<int key="NSvFlags">258</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -1569,14 +1567,13 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
</object>
</object>
<string key="NSFrameSize">{360, 290}</string>
<reference key="NSSuperview"/>
<object class="NSMutableString" key="NSClassName">
<characters key="NS.bytes">NSView</characters>
</object>
<string key="NSExtension">NSResponder</string>
</object>
<object class="NSCustomView" id="296911506">
<nil key="NSNextResponder"/>
<reference key="NSNextResponder"/>
<int key="NSvFlags">274</int>
<object class="NSMutableArray" key="NSSubviews">
<bool key="EncodedWithXMLCoder">YES</bool>
@ -1603,46 +1600,9 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
</object>
<object class="NSMutableArray" key="NSTableColumns">
<bool key="EncodedWithXMLCoder">YES</bool>
<object class="NSTableColumn" id="78872301">
<string key="NSIdentifier">Icon</string>
<double key="NSWidth">17</double>
<double key="NSMinWidth">17</double>
<double key="NSMaxWidth">17</double>
<object class="NSTableHeaderCell" key="NSHeaderCell">
<int key="NSCellFlags">75628096</int>
<int key="NSCellFlags2">2048</int>
<string key="NSContents"/>
<reference key="NSSupport" ref="26"/>
<object class="NSColor" key="NSBackgroundColor" id="665452585">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">headerColor</string>
<reference key="NSColor" ref="880039277"/>
</object>
<object class="NSColor" key="NSTextColor" id="390741217">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">headerTextColor</string>
<reference key="NSColor" ref="105940216"/>
</object>
</object>
<object class="NSImageCell" key="NSDataCell" id="477306431">
<int key="NSCellFlags">67239424</int>
<int key="NSCellFlags2">33554432</int>
<reference key="NSSupport" ref="737793924"/>
<int key="NSAlign">8</int>
<int key="NSScale">3</int>
<int key="NSStyle">0</int>
<bool key="NSAnimates">NO</bool>
</object>
<int key="NSResizingMask">3</int>
<bool key="NSIsResizeable">YES</bool>
<bool key="NSIsEditable">YES</bool>
<reference key="NSTableView" ref="423972458"/>
</object>
<object class="NSTableColumn" id="874876446">
<string key="NSIdentifier">Address</string>
<double key="NSWidth">337</double>
<string key="NSIdentifier">Tracker</string>
<double key="NSWidth">357</double>
<double key="NSMinWidth">40</double>
<double key="NSMaxWidth">1000</double>
<object class="NSTableHeaderCell" key="NSHeaderCell">
@ -1654,7 +1614,12 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<int key="NSColorSpace">3</int>
<bytes key="NSWhite">MC4zMzMzMzI5OQA</bytes>
</object>
<reference key="NSTextColor" ref="390741217"/>
<object class="NSColor" key="NSTextColor" id="390741217">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">headerTextColor</string>
<reference key="NSColor" ref="105940216"/>
</object>
</object>
<object class="NSTextFieldCell" key="NSDataCell" id="871658973">
<int key="NSCellFlags">337772096</int>
@ -1692,7 +1657,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<bytes key="NSWhite">MC41AA</bytes>
</object>
</object>
<double key="NSRowHeight">14</double>
<double key="NSRowHeight">57</double>
<int key="NSTvFlags">440401920</int>
<reference key="NSDelegate"/>
<reference key="NSDataSource"/>
@ -1739,7 +1704,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<reference key="NSVScroller" ref="964808471"/>
<reference key="NSHScroller" ref="265048045"/>
<reference key="NSContentView" ref="198254095"/>
<bytes key="NSScrollAmts">QSAAAEEgAABBgAAAQYAAAA</bytes>
<bytes key="NSScrollAmts">QSAAAEEgAABCbAAAQmwAAA</bytes>
</object>
<object class="NSSegmentedControl" id="899994514">
<reference key="NSNextResponder" ref="296911506"/>
@ -1780,6 +1745,7 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
</object>
</object>
<string key="NSFrameSize">{382, 352}</string>
<reference key="NSSuperview"/>
<object class="NSMutableString" key="NSClassName">
<characters key="NS.bytes">NSView</characters>
</object>
@ -1831,7 +1797,12 @@ AAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSBDb21wdXRlciwgSW5jLiwgMjAwNQAAAAA</bytes>
<int key="NSCellFlags2">2048</int>
<string key="NSContents">IP Address</string>
<reference key="NSSupport" ref="26"/>
<reference key="NSBackgroundColor" ref="665452585"/>
<object class="NSColor" key="NSBackgroundColor" id="665452585">
<int key="NSColorSpace">6</int>
<string key="NSCatalogName">System</string>
<string key="NSColorName">headerColor</string>
<reference key="NSColor" ref="880039277"/>
</object>
<reference key="NSTextColor" ref="390741217"/>
</object>
<object class="NSTextFieldCell" key="NSDataCell" id="762453246">
@ -5960,7 +5931,6 @@ AAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="874876446"/>
<reference ref="78872301"/>
</object>
<reference key="parent" ref="754568592"/>
</object>
@ -6211,20 +6181,6 @@ AAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
<reference key="object" ref="381060565"/>
<reference key="parent" ref="93205077"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1823</int>
<reference key="object" ref="78872301"/>
<object class="NSMutableArray" key="children">
<bool key="EncodedWithXMLCoder">YES</bool>
<reference ref="477306431"/>
</object>
<reference key="parent" ref="423972458"/>
</object>
<object class="IBObjectRecord">
<int key="objectID">1825</int>
<reference key="object" ref="477306431"/>
<reference key="parent" ref="78872301"/>
</object>
</object>
</object>
<object class="NSMutableDictionary" key="flattenedProperties">
@ -6579,8 +6535,6 @@ AAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
<string>1816.IBPluginDependency</string>
<string>1817.IBPluginDependency</string>
<string>1818.IBPluginDependency</string>
<string>1823.IBPluginDependency</string>
<string>1825.IBPluginDependency</string>
<string>28.IBPluginDependency</string>
<string>28.ImportedFromIB2</string>
<string>29.IBPluginDependency</string>
@ -7020,8 +6974,6 @@ AAAAAAAAAAAAAAAAAAB0ZXh0AAAAAENvcHlyaWdodCBBcHBsZSwgSW5jLiwgMjAwOQA</bytes>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>
<string>com.apple.InterfaceBuilder.CocoaPlugin</string>
<integer value="1"/>