Created prototype for a plugin browser

This commit is contained in:
Michael Starke
2018-10-11 15:21:19 +02:00
parent bf96867654
commit edf40e0cc7
6 changed files with 312 additions and 6 deletions

View File

@@ -226,6 +226,8 @@
4CC0D2CE17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0D2CD17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m */; }; 4CC0D2CE17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0D2CD17974A47000B4BDA /* MPCustomFieldTableViewDelegate.m */; };
4CC0D2D117974A5A000B4BDA /* MPAttachmentTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */; }; 4CC0D2D117974A5A000B4BDA /* MPAttachmentTableViewDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */; };
4CC281891C0F675B00B9174D /* HNHUi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC281881C0F675B00B9174D /* HNHUi.framework */; }; 4CC281891C0F675B00B9174D /* HNHUi.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CC281881C0F675B00B9174D /* HNHUi.framework */; };
4CC663E7216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC663E5216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m */; };
4CC663E8216F7A7100E33965 /* PluginRepositoryBrowserView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 4CC663E6216F7A7100E33965 /* PluginRepositoryBrowserView.xib */; };
4CC6DB7A17D23719002C6091 /* KPKNode+IconImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */; }; 4CC6DB7A17D23719002C6091 /* KPKNode+IconImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */; };
4CCA8E9B18D91ED9001A6754 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCA8E9A18D91ED9001A6754 /* Quartz.framework */; }; 4CCA8E9B18D91ED9001A6754 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4CCA8E9A18D91ED9001A6754 /* Quartz.framework */; };
4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCE8001D75CA48006AA951 /* MPArrayController.m */; }; 4CCCE8011D75CA48006AA951 /* MPArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CCCE8001D75CA48006AA951 /* MPArrayController.m */; };
@@ -755,6 +757,9 @@
4CC0D2CF17974A5A000B4BDA /* MPAttachmentTableViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAttachmentTableViewDelegate.h; sourceTree = "<group>"; }; 4CC0D2CF17974A5A000B4BDA /* MPAttachmentTableViewDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MPAttachmentTableViewDelegate.h; sourceTree = "<group>"; };
4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAttachmentTableViewDelegate.m; sourceTree = "<group>"; }; 4CC0D2D017974A5A000B4BDA /* MPAttachmentTableViewDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MPAttachmentTableViewDelegate.m; sourceTree = "<group>"; };
4CC281881C0F675B00B9174D /* HNHUi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HNHUi.framework; path = Carthage/Build/Mac/HNHUi.framework; sourceTree = "<group>"; }; 4CC281881C0F675B00B9174D /* HNHUi.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = HNHUi.framework; path = Carthage/Build/Mac/HNHUi.framework; sourceTree = "<group>"; };
4CC663E4216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MPPluginRepositoryBrowserViewController.h; sourceTree = "<group>"; };
4CC663E5216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MPPluginRepositoryBrowserViewController.m; sourceTree = "<group>"; };
4CC663E6216F7A7100E33965 /* PluginRepositoryBrowserView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PluginRepositoryBrowserView.xib; sourceTree = "<group>"; };
4CC6DB7817D23719002C6091 /* KPKNode+IconImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KPKNode+IconImage.h"; sourceTree = "<group>"; }; 4CC6DB7817D23719002C6091 /* KPKNode+IconImage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "KPKNode+IconImage.h"; sourceTree = "<group>"; };
4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KPKNode+IconImage.m"; sourceTree = "<group>"; }; 4CC6DB7917D23719002C6091 /* KPKNode+IconImage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "KPKNode+IconImage.m"; sourceTree = "<group>"; };
4CCA7EEC1797866F00B0B55E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/GeneralSettings.strings; sourceTree = "<group>"; }; 4CCA7EEC1797866F00B0B55E /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/GeneralSettings.strings; sourceTree = "<group>"; };
@@ -1556,6 +1561,9 @@
4C73B6EE215E64A7009787F7 /* MPWelcomeViewController.h */, 4C73B6EE215E64A7009787F7 /* MPWelcomeViewController.h */,
4C73B6EF215E64A7009787F7 /* MPWelcomeViewController.m */, 4C73B6EF215E64A7009787F7 /* MPWelcomeViewController.m */,
4C7F8B6A1A10B68400CCB83D /* WelcomeView.xib */, 4C7F8B6A1A10B68400CCB83D /* WelcomeView.xib */,
4CC663E4216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.h */,
4CC663E5216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m */,
4CC663E6216F7A7100E33965 /* PluginRepositoryBrowserView.xib */,
); );
name = "View Controller"; name = "View Controller";
sourceTree = "<group>"; sourceTree = "<group>";
@@ -1838,6 +1846,7 @@
4C3826B31AD04D8E007D7D67 /* 38_SambaUnmountTemplate.pdf in Resources */, 4C3826B31AD04D8E007D7D67 /* 38_SambaUnmountTemplate.pdf in Resources */,
4CB9339916D3A0DD00A13B5D /* Credits.rtf in Resources */, 4CB9339916D3A0DD00A13B5D /* Credits.rtf in Resources */,
4C08ACEA204F01C700863D99 /* keyboardTemplate.pdf in Resources */, 4C08ACEA204F01C700863D99 /* keyboardTemplate.pdf in Resources */,
4CC663E8216F7A7100E33965 /* PluginRepositoryBrowserView.xib in Resources */,
4C0F04412147FB49000B8568 /* OpenPanelAccessoryView.xib in Resources */, 4C0F04412147FB49000B8568 /* OpenPanelAccessoryView.xib in Resources */,
4C6DCC451FA2457900C8AD3F /* ContextBar.xib in Resources */, 4C6DCC451FA2457900C8AD3F /* ContextBar.xib in Resources */,
4C431BCF16E2BAB000700A81 /* OverlayWindow.xib in Resources */, 4C431BCF16E2BAB000700A81 /* OverlayWindow.xib in Resources */,
@@ -2024,6 +2033,7 @@
4CF6C3021FBF39BF0055AD03 /* MPPluginTabelCellView.m in Sources */, 4CF6C3021FBF39BF0055AD03 /* MPPluginTabelCellView.m in Sources */,
4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */, 4C10412C178CDD44001B5239 /* NSDate+Humanized.m in Sources */,
4C2F17A21FD69BCA0097418D /* MPUserNotificationCenterDelegate.m in Sources */, 4C2F17A21FD69BCA0097418D /* MPUserNotificationCenterDelegate.m in Sources */,
4CC663E7216F7A7100E33965 /* MPPluginRepositoryBrowserViewController.m in Sources */,
4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */, 4C0C59F118B17F10009C7B76 /* DDHotKeyUtilities.m in Sources */,
4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */, 4CEE46DD181C301D006BF1E5 /* MPAutotypeDaemon.m in Sources */,
4C50CC041F6C18830095629D /* MPCollectionViewItem.m in Sources */, 4C50CC041F6C18830095629D /* MPCollectionViewItem.m in Sources */,

View File

@@ -133,7 +133,9 @@ NSString *const MPPluginHostPluginBundleIdentifiyerKey = @"MPPluginHostPluginBun
- (void)loadPlugins { - (void)loadPlugins {
[MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) { [MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
[self _loadPlugins:availablePlugins]; dispatch_async(dispatch_get_main_queue(), ^{
[self _loadPlugins:availablePlugins];
});
}]; }];
} }

View File

@@ -0,0 +1,20 @@
//
// MPPluginRepositoryBrowserViewController.h
// MacPass
//
// Created by Michael Starke on 11.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface MPPluginRepositoryBrowserViewController : NSViewController
- (IBAction)refresh:(id)sender;
- (IBAction)closeBrowser:(id)sender;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,81 @@
//
// MPPluginRepositoryBrowserViewController.m
// MacPass
//
// Created by Michael Starke on 11.10.18.
// Copyright © 2018 HicknHack Software GmbH. All rights reserved.
//
#import "MPPluginRepositoryBrowserViewController.h"
#import "MPPluginRepository.h"
#import "MPPluginRepositoryItem.h"
NSString *MPPluginBrowserColumnName = @"MPPluginBrowserColumnName";
NSString *MPPluginBrowserColumnCurrentVersion = @"MPPluginBrowserColumnCurrentVersion";
NSString *MPPluginBrowserColumnInstalledVersion = @"MPPluginBrowserColumnInstalledVersion";
@interface MPPluginRepositoryBrowserViewController () <NSTableViewDelegate, NSTableViewDataSource>
@property (copy) NSArray<MPPluginRepositoryItem *>* repositoryItems;
@property (strong) IBOutlet NSTableView *itemTable;
@end
@implementation MPPluginRepositoryBrowserViewController
- (NSNibName)nibName {
return @"PluginRepositoryBrowserView";
}
- (void)viewDidLoad {
self.itemTable.tableColumns[0].identifier = MPPluginBrowserColumnName;
self.itemTable.tableColumns[1].identifier = MPPluginBrowserColumnCurrentVersion;
self.itemTable.tableColumns[2].identifier = MPPluginBrowserColumnInstalledVersion;
[super viewDidLoad];
[self _refreshRepository];
}
- (void)refresh:(id)sender {
[self _refreshRepository];
}
- (IBAction)closeBrowser:(id)sender {
[self.presentingViewController dismissViewController:self];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView {
return self.repositoryItems.count > 0 ? 100 : 0;
}
- (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row {
MPPluginRepositoryItem *item = self.repositoryItems.firstObject;
if([tableColumn.identifier isEqualToString:MPPluginBrowserColumnName]) {
NSTableCellView *view = [tableView makeViewWithIdentifier:@"NameCellView" owner:self];
view.textField.stringValue = item.name;
return view;
}
if([tableColumn.identifier isEqualToString:MPPluginBrowserColumnCurrentVersion]) {
NSTableCellView *view = [tableView makeViewWithIdentifier:@"CurrentVersionCellView" owner:self];
view.textField.stringValue = item.currentVersion;
return view;
}
NSTableCellView *view = [tableView makeViewWithIdentifier:@"InstalledVersionCellView" owner:self];
view.textField.stringValue = item.descriptionText;
return view;
}
- (void)_refreshRepository {
[MPPluginRepository.defaultRepository fetchRepositoryDataCompletionHandler:^(NSArray<MPPluginRepositoryItem *> * _Nonnull availablePlugins) {
dispatch_async(dispatch_get_main_queue(), ^{
self.repositoryItems = availablePlugins;
[self.itemTable reloadData];
});
}];
}
@end

View File

@@ -26,8 +26,7 @@
#import "MPPlugin.h" #import "MPPlugin.h"
#import "MPPlugin_Private.h" #import "MPPlugin_Private.h"
#import "MPPluginConstants.h" #import "MPPluginConstants.h"
#import "MPPluginRepository.h" #import "MPPluginRepositoryBrowserViewController.h"
#import "MPPluginRepositoryItem.h"
#import "MPConstants.h" #import "MPConstants.h"
#import "MPSettingsHelper.h" #import "MPSettingsHelper.h"
@@ -184,7 +183,8 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
#pragma mark - Actions #pragma mark - Actions
- (IBAction)browsePlugins:(id)sender { - (IBAction)browsePlugins:(id)sender {
[NSWorkspace.sharedWorkspace openURL:[NSApp applicationSupportDirectoryURL:YES]]; [self presentViewControllerAsSheet:[[MPPluginRepositoryBrowserViewController alloc] init]];
// [NSWorkspace.sharedWorkspace openURL:[NSApp applicationSupportDirectoryURL:YES]];
} }
- (IBAction)addOrRemovePlugin:(id)sender { - (IBAction)addOrRemovePlugin:(id)sender {
@@ -224,7 +224,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
- (void)_addPlugin:(NSURL *)bundleURL { - (void)_addPlugin:(NSURL *)bundleURL {
NSError *error; NSError *error;
if(![[MPPluginHost sharedHost] installPluginAtURL:bundleURL error:&error]) { if(![MPPluginHost.sharedHost installPluginAtURL:bundleURL error:&error]) {
[NSApp presentError:error modalForWindow:self.view.window delegate:nil didPresentSelector:NULL contextInfo:NULL]; [NSApp presentError:error modalForWindow:self.view.window delegate:nil didPresentSelector:NULL contextInfo:NULL];
} }
else { else {
@@ -252,7 +252,7 @@ typedef NS_ENUM(NSUInteger, MPPluginSegmentType) {
- (void)_removePlugin:(MPPlugin *)plugin { - (void)_removePlugin:(MPPlugin *)plugin {
NSError *error; NSError *error;
if(![[MPPluginHost sharedHost] uninstallPlugin:plugin error:&error]) { if(![MPPluginHost.sharedHost uninstallPlugin:plugin error:&error]) {
[NSApp presentError:error modalForWindow:self.view.window delegate:nil didPresentSelector:NULL contextInfo:NULL]; [NSApp presentError:error modalForWindow:self.view.window delegate:nil didPresentSelector:NULL contextInfo:NULL];
} }
else { else {

View File

@@ -0,0 +1,193 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14313.18" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14313.18"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="MPPluginRepositoryBrowserViewController">
<connections>
<outlet property="itemTable" destination="gDR-Fx-c0h" id="yYx-qm-i7K"/>
<outlet property="view" destination="Hz6-mo-xeY" id="0bl-1N-x8E"/>
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<customView id="Hz6-mo-xeY">
<rect key="frame" x="0.0" y="0.0" width="440" height="513"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<subviews>
<scrollView autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="V1g-KK-vjw">
<rect key="frame" x="20" y="61" width="400" height="432"/>
<clipView key="contentView" id="Sqy-VI-iH4">
<rect key="frame" x="1" y="0.0" width="398" height="431"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="uVe-04-Now" viewBased="YES" id="gDR-Fx-c0h">
<rect key="frame" x="0.0" y="0.0" width="398" height="408"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn width="124" minWidth="40" maxWidth="1000" id="qP8-eW-n9j">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="cg1-Wr-3Ue">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="NameCellView" id="67K-DS-g25">
<rect key="frame" x="1" y="1" width="124" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LS1-kl-Nlg">
<rect key="frame" x="0.0" y="0.0" width="124" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="fGy-c8-mXg">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="LS1-kl-Nlg" id="ffz-9R-nz9"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn width="112" minWidth="10" maxWidth="3.4028234663852886e+38" id="xwz-Ka-TIh">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Current Version">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="Gzp-74-qk9">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView identifier="CurrentVersionCellView" id="4ru-Vq-zSo">
<rect key="frame" x="128" y="1" width="112" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="b4M-Vw-5Xt">
<rect key="frame" x="0.0" y="0.0" width="112" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="IHy-3y-4f5">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="b4M-Vw-5Xt" id="vbR-aL-vZh"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
<tableColumn identifier="InstalledVersionCellView" width="109" minWidth="10" maxWidth="3.4028234663852886e+38" id="mb4-uD-bVk">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left" title="Installed Version">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableHeaderCell>
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="Kl6-i5-XNe">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
<prototypeCellViews>
<tableCellView id="hzK-ST-sjE">
<rect key="frame" x="243" y="1" width="109" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cLf-rq-sQD">
<rect key="frame" x="0.0" y="0.0" width="109" height="17"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="Exn-N8-cbq">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
<connections>
<outlet property="textField" destination="cLf-rq-sQD" id="Yjb-eE-Uhc"/>
</connections>
</tableCellView>
</prototypeCellViews>
</tableColumn>
</tableColumns>
<connections>
<outlet property="dataSource" destination="-2" id="h4c-vn-wkB"/>
<outlet property="delegate" destination="-2" id="Z3g-L4-Koe"/>
</connections>
</tableView>
</subviews>
</clipView>
<constraints>
<constraint firstAttribute="width" relation="greaterThanOrEqual" constant="400" id="gYM-eK-y5v"/>
</constraints>
<scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="ajb-Vb-WhY">
<rect key="frame" x="1" y="415" width="398" height="16"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" doubleValue="1" horizontal="NO" id="3eJ-oK-GNt">
<rect key="frame" x="224" y="17" width="15" height="102"/>
<autoresizingMask key="autoresizingMask"/>
</scroller>
<tableHeaderView key="headerView" id="uVe-04-Now">
<rect key="frame" x="0.0" y="0.0" width="398" height="23"/>
<autoresizingMask key="autoresizingMask"/>
</tableHeaderView>
</scrollView>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="bGv-Zc-Vrk">
<rect key="frame" x="14" y="13" width="87" height="32"/>
<buttonCell key="cell" type="push" title="Refresh" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="NZw-nO-lZ3">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="refresh:" target="-2" id="xld-yu-3Q9"/>
</connections>
</button>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Pkh-la-7FU">
<rect key="frame" x="354" y="13" width="72" height="32"/>
<buttonCell key="cell" type="push" title="Done" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="j9a-fn-Pye">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="closeBrowser:" target="-2" id="FVU-rJ-Pxm"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="Pkh-la-7FU" firstAttribute="top" secondItem="V1g-KK-vjw" secondAttribute="bottom" constant="20" symbolic="YES" id="30X-fR-rks"/>
<constraint firstItem="V1g-KK-vjw" firstAttribute="top" secondItem="Hz6-mo-xeY" secondAttribute="top" constant="20" symbolic="YES" id="3jQ-NX-W3e"/>
<constraint firstAttribute="bottom" secondItem="Pkh-la-7FU" secondAttribute="bottom" constant="20" symbolic="YES" id="AwW-xp-Lps"/>
<constraint firstAttribute="trailing" secondItem="V1g-KK-vjw" secondAttribute="trailing" constant="20" symbolic="YES" id="DVA-MO-e4e"/>
<constraint firstItem="bGv-Zc-Vrk" firstAttribute="top" secondItem="V1g-KK-vjw" secondAttribute="bottom" constant="20" symbolic="YES" id="Qfh-Wb-IV3"/>
<constraint firstItem="V1g-KK-vjw" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" symbolic="YES" id="SQs-j2-6HH"/>
<constraint firstAttribute="bottom" secondItem="bGv-Zc-Vrk" secondAttribute="bottom" constant="20" symbolic="YES" id="hyU-hm-uRL"/>
<constraint firstAttribute="trailing" secondItem="Pkh-la-7FU" secondAttribute="trailing" constant="20" symbolic="YES" id="iTm-72-HFD"/>
<constraint firstItem="Pkh-la-7FU" firstAttribute="leading" relation="greaterThanOrEqual" secondItem="bGv-Zc-Vrk" secondAttribute="trailing" constant="12" symbolic="YES" id="lUQ-jf-KWR"/>
<constraint firstItem="bGv-Zc-Vrk" firstAttribute="leading" secondItem="Hz6-mo-xeY" secondAttribute="leading" constant="20" id="tk3-kF-k22"/>
</constraints>
<point key="canvasLocation" x="-377" y="110"/>
</customView>
</objects>
</document>