├── .gitignore ├── .gitmodules ├── CRCconstants.h ├── CRCconstants.m ├── CocoaRestClient-Info.plist ├── CocoaRestClient.xcodeproj ├── dev.pbxuser ├── dev.perspectivev3 ├── mmattozzi.mode1v3 ├── mmattozzi.pbxuser └── project.pbxproj ├── CocoaRestClient.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ ├── CocoaRestClient.xccheckout │ └── IDEWorkspaceChecks.plist ├── CocoaRestClient ├── CocoaRestClient.entitlements └── Images.xcassets │ └── AppIcon.appiconset │ ├── Contents.json │ ├── icon_128x128.png │ ├── icon_16x16.png │ ├── icon_256x256-2.png │ ├── icon_256x256.png │ ├── icon_32x32-1.png │ ├── icon_32x32-2.png │ ├── icon_32x32.png │ ├── icon_512x512-1.png │ ├── icon_512x512.png │ └── icon_512x512@2x.png ├── CocoaRestClientTests ├── Info.plist └── MainWindowControllerTests.m ├── English.lproj ├── DiffWindow.xib ├── ExportRequests.xib ├── FastSearchSavedRequests.xib ├── InfoPlist.strings ├── MainMenu.xib ├── MainWindow.xib ├── Preferences.xib ├── Welcome.xib ├── background-header.png ├── cocoaRestClient.icns ├── document-icon.png ├── dsa_pub.pem └── motd.txt ├── LICENSE.txt ├── Podfile ├── README.md ├── ReleaseNotes ├── 1.2.2.html ├── 1.2.3.html ├── 1.2.4.html ├── 1.3.0.html ├── 1.3.1.html ├── 1.3.10.html ├── 1.3.11.html ├── 1.3.12.html ├── 1.3.13.html ├── 1.3.14.html ├── 1.3.15.html ├── 1.3.16.html ├── 1.3.17.html ├── 1.3.2.html ├── 1.3.3.html ├── 1.3.4.html ├── 1.3.5.html ├── 1.3.6.html ├── 1.3.7.html ├── 1.3.8.html ├── 1.3.9.html ├── 1.4.0.html ├── 1.4.1.html ├── 1.4.2.html ├── 1.4.3.html ├── 1.4.4.html ├── 1.4.5.html ├── 1.4.6.html └── 1.4.7.html ├── core ├── CheckableRequestWrapper.h ├── CheckableRequestWrapper.m ├── CocoaRestClientAppDelegate.h ├── CocoaRestClientAppDelegate.m ├── CocoaRestClient_Prefix.pch ├── ContentTypes.h ├── ContentTypes.m ├── DiffWindowController.h ├── DiffWindowController.m ├── ExportRequestsController.h ├── ExportRequestsController.m ├── FastSearchSavedRequestsController.h ├── FastSearchSavedRequestsController.m ├── MainWindowController.h ├── MainWindowController.m ├── PreferencesController.h ├── PreferencesController.m ├── SaveRequestPanelController.h ├── SaveRequestPanelController.m ├── SavedRequestsDataSource.h ├── SavedRequestsDataSource.m ├── SelectableSavedRequestWrapper.h ├── SelectableSavedRequestWrapper.m ├── TimeoutPanelController.h ├── TimeoutPanelController.m ├── WelcomeController.h ├── WelcomeController.m └── main.m ├── defaults.plist ├── request ├── CRCFileRequest.h ├── CRCFileRequest.m ├── CRCFormEncodedRequest.h ├── CRCFormEncodedRequest.m ├── CRCMultipartRequest.h ├── CRCMultipartRequest.m ├── CRCRawRequest.h ├── CRCRawRequest.m ├── CRCRequest.h ├── CRCRequest.m ├── CRCSavedRequestFolder.h ├── CRCSavedRequestFolder.m ├── NSData+gzip.h └── NSData+gzip.m ├── screenshots ├── cocoa-rest-client-1-large.png ├── cocoa-rest-client-1.jpg ├── cocoa-rest-client-1.png ├── cocoa-rest-client-1_large.jpg ├── cocoa-rest-client-2-large.png ├── cocoa-rest-client-2.jpg ├── cocoa-rest-client-2.png ├── cocoa-rest-client-2_large.jpg ├── cocoa-rest-client-3-large.png ├── cocoa-rest-client-3.jpg ├── cocoa-rest-client-3.png ├── cocoa-rest-client-3_large.jpg ├── cocoa-rest-client-4-large.png ├── cocoa-rest-client-4.jpg ├── cocoa-rest-client-4.png ├── cocoa-rest-client-4_large.jpg ├── cocoa-rest-client-5-large.png ├── cocoa-rest-client-5.jpg ├── cocoa-rest-client-5.png ├── cocoa-rest-client-5_large.jpg ├── cocoa-rest-client-6-large.png └── cocoa-rest-client-7-large.png └── view ├── ACEView+TouchBarExtension.h ├── ACEView+TouchBarExtension.m ├── CRCDrawerView.h ├── CRCDrawerView.m ├── CRCHTTPHeaderCell.h ├── CRCHTTPHeaderCell.m ├── CRCTopView.h ├── CRCTopView.m ├── DMSlidingTabItemView.h ├── DMSlidingTabItemView.m ├── DMSlidingTabView.h ├── DMSlidingTabView.m ├── DMSlidingTabViewItemProtocol.h ├── FastSearchSavedRequestTextCellView.h ├── FastSearchSavedRequestTextCellView.m ├── HighlightingTypeManager.h ├── HighlightingTypeManager.m ├── NSTextView+TouchBarExtension.h ├── NSTextView+TouchBarExtension.m ├── TabbingTableView.h ├── TabbingTableView.m ├── TableRowAndColumn.h └── TableRowAndColumn.m /.gitignore: -------------------------------------------------------------------------------- 1 | CocoaRestClient.xcodeproj/project.xcworkspace 2 | CocoaRestClient.xcodeproj/xcuserdata 3 | .DS_Store 4 | CocoaRestClient.xcworkspace/xcuserdata/ 5 | Podfile.lock 6 | Pods 7 | Build 8 | DerivedData 9 | *.xcscmblueprint 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "Fragaria"] 2 | path = Fragaria 3 | url = git@github.com:darvin/Fragaria.git 4 | -------------------------------------------------------------------------------- /CRCconstants.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCconstants.h 3 | // 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | #define APPLICATION_NAME @"CocoaRestClient" 12 | #define DATAFILE_NAME @"CocoaRestClient.savedRequests" 13 | #define BACKUP_DATAFILE_1_3_8 @"CocoaRestClient.savedRequests.backup-1.3.8" 14 | 15 | FOUNDATION_EXPORT NSString * const FOLLOW_REDIRECTS; 16 | FOUNDATION_EXPORT NSString * const APPLY_HTTP_METHOD_ON_REDIRECT; 17 | FOUNDATION_EXPORT NSString * const SYNTAX_HIGHLIGHT; 18 | FOUNDATION_EXPORT NSString * const RAW_REQUEST_BODY; 19 | FOUNDATION_EXPORT NSString * const RESPONSE_TIMEOUT; 20 | FOUNDATION_EXPORT NSString * const SAVED_DRAWER_SIZE; 21 | FOUNDATION_EXPORT NSString * const THEME; 22 | FOUNDATION_EXPORT NSString * const DARK_THEME; 23 | FOUNDATION_EXPORT NSUInteger const DEFAULT_FONT_SIZE; 24 | FOUNDATION_EXPORT NSString * const SHOW_LINE_NUMBERS; 25 | FOUNDATION_EXPORT NSString * const DISABLE_ANIMATIONS; 26 | FOUNDATION_EXPORT NSString * const DISABLE_COOKIES; 27 | FOUNDATION_EXPORT NSString * const FILE_REQUEST_BODY; 28 | FOUNDATION_EXPORT NSString * const ALLOW_SELF_SIGNED_CERTS; 29 | FOUNDATION_EXPORT NSString * const SHOW_SAVED_REQUESTS_MENU_TITLE; 30 | FOUNDATION_EXPORT NSString * const HIDE_SAVED_REQUESTS_MENU_TITLE; 31 | FOUNDATION_EXPORT NSString * const SAVED_REQUESTS_VIEW_WIDTH; 32 | FOUNDATION_EXPORT NSString * const DEFAULT_CONTENT_TYPE; 33 | 34 | @interface CRCConstants : NSObject 35 | 36 | @end 37 | -------------------------------------------------------------------------------- /CRCconstants.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCconstants.m 3 | // 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // 7 | // 8 | 9 | #import "CRCConstants.h" 10 | 11 | @implementation CRCConstants 12 | 13 | NSString * const FOLLOW_REDIRECTS = @"followRedirects"; 14 | NSString * const APPLY_HTTP_METHOD_ON_REDIRECT = @"applyHttpMethodOnRedirect"; 15 | NSString * const SYNTAX_HIGHLIGHT = @"UIMenuSyntaxHighlight"; 16 | NSString * const RAW_REQUEST_BODY = @"UIRawRequestBody"; 17 | NSString * const RESPONSE_TIMEOUT = @"responseTimeout"; 18 | NSString * const SAVED_DRAWER_SIZE = @"savedDrawerSize"; 19 | NSString * const THEME = @"theme"; 20 | NSString * const DARK_THEME = @"darkTheme"; 21 | NSUInteger const DEFAULT_FONT_SIZE = 12; 22 | NSString * const SHOW_LINE_NUMBERS = @"showLineNumbers"; 23 | NSString * const DISABLE_ANIMATIONS = @"UIDisableAnimations"; 24 | NSString * const DISABLE_COOKIES = @"disableCookies"; 25 | NSString * const FILE_REQUEST_BODY = @"UIFileRequestBody"; 26 | NSString * const ALLOW_SELF_SIGNED_CERTS = @"allowSelfSignedCerts"; 27 | NSString * const SHOW_SAVED_REQUESTS_MENU_TITLE = @"Show Saved Requests Sidebar"; 28 | NSString * const HIDE_SAVED_REQUESTS_MENU_TITLE = @"Hide Saved Requests Sidebar"; 29 | NSString * const SAVED_REQUESTS_VIEW_WIDTH = @"savedRequestsViewWidth"; 30 | NSString * const DEFAULT_CONTENT_TYPE = @"defaultContentType"; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /CocoaRestClient-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleDisplayName 8 | Cocoa Rest Client 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | $(CURRENT_PROJECT_VERSION) 25 | LSApplicationCategoryType 26 | public.app-category.utilities 27 | LSMinimumSystemVersion 28 | ${MACOSX_DEPLOYMENT_TARGET} 29 | NSAppTransportSecurity 30 | 31 | NSAllowsArbitraryLoads 32 | 33 | 34 | NSMainNibFile 35 | MainMenu 36 | NSPrincipalClass 37 | NSApplication 38 | SUEnableSystemProfiling 39 | 40 | SUFeedURL 41 | https://mmattozzi.github.io/cocoa-rest-client/appcast.xml 42 | SUPublicDSAKeyFile 43 | dsa_pub.pem 44 | kCRCHeadersUserDefaultsKey 45 | 46 | Accept 47 | Accept-Charset 48 | Accept-Encoding 49 | Accept-Language 50 | Accept-Datetime 51 | Authorization 52 | Cache-Control 53 | Connection 54 | Cookie 55 | Content-Length 56 | Content-MD5 57 | Content-Type 58 | Date 59 | Expect 60 | From 61 | Host 62 | If-Match 63 | If-Modified-Since 64 | If-None-Match 65 | If-Range 66 | If-Unmodified-Since 67 | Max-Forwards 68 | Pragma 69 | Proxy-Authorization 70 | Range 71 | Referer 72 | TE 73 | Upgrade 74 | User-Agent 75 | Via 76 | Warning 77 | 78 | 79 | 80 | -------------------------------------------------------------------------------- /CocoaRestClient.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /CocoaRestClient.xcworkspace/xcshareddata/CocoaRestClient.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 0771223B-C4FF-43BD-9172-5F03C6854A68 9 | IDESourceControlProjectName 10 | CocoaRestClient 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 1E2D1B7A28CCAD432519863A54B954C933696C3B 14 | ssh://github.com/mmattozzi/cocoa-rest-client.git 15 | 378B54B5205DE31B3B2EBDA14687C757C53E503B 16 | https://github.com/mmattozzi/ACEView.git 17 | 6AA9B563339F4175433F6583E018B0E6CF800437 18 | https://github.com/ajaxorg/ace-builds.git 19 | 20 | IDESourceControlProjectPath 21 | CocoaRestClient.xcworkspace 22 | IDESourceControlProjectRelativeInstallPathDictionary 23 | 24 | 1E2D1B7A28CCAD432519863A54B954C933696C3B 25 | .. 26 | 378B54B5205DE31B3B2EBDA14687C757C53E503B 27 | ../../ACEView 28 | 6AA9B563339F4175433F6583E018B0E6CF800437 29 | ../../ACEView/ACEView/Dependencies/ace 30 | 31 | IDESourceControlProjectURL 32 | ssh://github.com/mmattozzi/cocoa-rest-client.git 33 | IDESourceControlProjectVersion 34 | 111 35 | IDESourceControlProjectWCCIdentifier 36 | 1E2D1B7A28CCAD432519863A54B954C933696C3B 37 | IDESourceControlProjectWCConfigurations 38 | 39 | 40 | IDESourceControlRepositoryExtensionIdentifierKey 41 | public.vcs.git 42 | IDESourceControlWCCIdentifierKey 43 | 6AA9B563339F4175433F6583E018B0E6CF800437 44 | IDESourceControlWCCName 45 | ace 46 | 47 | 48 | IDESourceControlRepositoryExtensionIdentifierKey 49 | public.vcs.git 50 | IDESourceControlWCCIdentifierKey 51 | 378B54B5205DE31B3B2EBDA14687C757C53E503B 52 | IDESourceControlWCCName 53 | ACEView 54 | 55 | 56 | IDESourceControlRepositoryExtensionIdentifierKey 57 | public.vcs.git 58 | IDESourceControlWCCIdentifierKey 59 | 1E2D1B7A28CCAD432519863A54B954C933696C3B 60 | IDESourceControlWCCName 61 | cocoa-rest-client 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /CocoaRestClient.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CocoaRestClient/CocoaRestClient.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-jit 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "size" : "16x16", 5 | "idiom" : "mac", 6 | "filename" : "icon_16x16.png", 7 | "scale" : "1x" 8 | }, 9 | { 10 | "size" : "16x16", 11 | "idiom" : "mac", 12 | "filename" : "icon_32x32-2.png", 13 | "scale" : "2x" 14 | }, 15 | { 16 | "size" : "32x32", 17 | "idiom" : "mac", 18 | "filename" : "icon_32x32.png", 19 | "scale" : "1x" 20 | }, 21 | { 22 | "size" : "32x32", 23 | "idiom" : "mac", 24 | "filename" : "icon_32x32-1.png", 25 | "scale" : "2x" 26 | }, 27 | { 28 | "size" : "128x128", 29 | "idiom" : "mac", 30 | "filename" : "icon_128x128.png", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "size" : "128x128", 35 | "idiom" : "mac", 36 | "filename" : "icon_256x256-2.png", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "size" : "256x256", 41 | "idiom" : "mac", 42 | "filename" : "icon_256x256.png", 43 | "scale" : "1x" 44 | }, 45 | { 46 | "size" : "256x256", 47 | "idiom" : "mac", 48 | "filename" : "icon_512x512-1.png", 49 | "scale" : "2x" 50 | }, 51 | { 52 | "size" : "512x512", 53 | "idiom" : "mac", 54 | "filename" : "icon_512x512.png", 55 | "scale" : "1x" 56 | }, 57 | { 58 | "size" : "512x512", 59 | "idiom" : "mac", 60 | "filename" : "icon_512x512@2x.png", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_128x128.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_16x16.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_256x256-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_256x256-2.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_256x256.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32-1.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32-2.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_32x32.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512-1.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512.png -------------------------------------------------------------------------------- /CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/CocoaRestClient/Images.xcassets/AppIcon.appiconset/icon_512x512@2x.png -------------------------------------------------------------------------------- /CocoaRestClientTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /CocoaRestClientTests/MainWindowControllerTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowControllerTests.m 3 | // CocoaRestClientTests 4 | // 5 | // Created by Mike Mattozzi on 4/21/19. 6 | // 7 | 8 | #import 9 | #import "MainWindowController.h" 10 | 11 | @interface MainWindowControllerTests : XCTestCase { 12 | MainWindowController *mainWindowController; 13 | } 14 | 15 | @end 16 | 17 | @implementation MainWindowControllerTests 18 | 19 | - (void)setUp { 20 | [super setUp]; 21 | // Put setup code here. This method is called before the invocation of each test method in the class. 22 | mainWindowController = [[MainWindowController alloc] init]; 23 | } 24 | 25 | - (void)tearDown { 26 | // Put teardown code here. This method is called after the invocation of each test method in the class. 27 | [super tearDown]; 28 | } 29 | 30 | - (void)testEnvVariableOneSubstitution { 31 | NSDictionary *environmentVariables = [[NSProcessInfo processInfo] environment]; 32 | NSString *user = [environmentVariables objectForKey:@"USER"]; 33 | NSString *expected = [NSString stringWithFormat:@"User has %@ username", user]; 34 | 35 | NSString *result = [mainWindowController substituteEnvVariables:@"User has ${USER} username"]; 36 | 37 | XCTAssertEqualObjects(expected, result); 38 | } 39 | 40 | - (void)testEnvVariableTwoSubstitutions { 41 | NSDictionary *environmentVariables = [[NSProcessInfo processInfo] environment]; 42 | NSString *user = [environmentVariables objectForKey:@"USER"]; 43 | NSString *shell = [environmentVariables objectForKey:@"SHELL"]; 44 | NSString *expected = [NSString stringWithFormat:@"User has %@ username, and shell %@", user, shell]; 45 | 46 | NSString *result = [mainWindowController substituteEnvVariables:@"User has ${USER} username, and shell ${SHELL}"]; 47 | 48 | XCTAssertEqualObjects(expected, result); 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /English.lproj/DiffWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /English.lproj/ExportRequests.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 53 | 67 | 78 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 129 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | -------------------------------------------------------------------------------- /English.lproj/FastSearchSavedRequests.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 99 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | -------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /English.lproj/Preferences.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 43 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /English.lproj/Welcome.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | 52 | 53 | 54 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /English.lproj/background-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/English.lproj/background-header.png -------------------------------------------------------------------------------- /English.lproj/cocoaRestClient.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/English.lproj/cocoaRestClient.icns -------------------------------------------------------------------------------- /English.lproj/document-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/English.lproj/document-icon.png -------------------------------------------------------------------------------- /English.lproj/dsa_pub.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIDOzCCAi0GByqGSM44BAEwggIgAoIBAQDZey2bDGM8RV8pSvIT6f89vvStGr0/ 3 | PGrStzF70RfZxlR6v8TSvpKJAtIBI6esmnnGUY13w8woLH20RHWCMFviMYvOCzz6 4 | 44+4G2NsTkpWxWKGb6l2a8BjryErJvirDe5IDONBDe6iJ3VR6S7NtEfjNfYuZRvG 5 | pWLEUJj/OBNgEws6tD1Wb7fxvkNT4fHfDpyfkbFXbM738vVgXyESKbmOP2MMvCx2 6 | 5PplSsnt8nP8Gd+mL399le4tlWF4n2x1+dOv4GrZdXz4Hsae/sm8h8mAyxyW0XCN 7 | TG6Haw0h0w85ehDi7aba3HNaxNZYIT03BtQ8CaEHn3POzpxDBbbqMpONAhUAwwwJ 8 | FxN+DnBzxUBUwc9d18mGfoUCggEADSSZ3sFsJMrGcV1SIOG9qGkGebqvPiWsaKal 9 | E+cyowrgWI0SHqGjKBUOF3qtvKtha2hqH158krcQCNHjXpX+r8eryQ42WFsfJDpq 10 | WMA+pX/loPEh2AxhD79hVTogyfoBrlda7BmT2kf6iQ1W2FrHnwH3qB4l9HgABwy2 11 | MNfZwVW/XIOOElxa3WDKEgsrINO4pJSYPtwnw6BLD88szNtllYHp54HSJvY5hHRh 12 | fT/Epls7kfbvQoLDySn+3hNPV1GomR3m+B+8tTMjU072ZrOSUpkn12WzCP0QhxuX 13 | h9CZkNW/FSNi+qqZRibNp8Uqsmyk8lrEVhSVTtGXuuj0kb5haQOCAQYAAoIBAQCY 14 | /z+xcD7F2GKf//lxQqmS7iIBaPfdpK580Juef9PiJpklCTKZGhUSnnnAVjHss2yO 15 | hg+S37bYMbYGLhtyCg+tt25J8ZbqiKEgNWGTZE9Bhtce4QiRrj1GnOF0kzYMifwH 16 | ffg9nzYGunxmrPPGzxNbA4u3scbVjNARaIyu8vu1RB425pjpLgd1UP+IsleoypAn 17 | sFP3xiW+YGw9qGsar7MTJM99hXkSWrdQbOGSlPZSK6cm9cXYQn7vnLA3qlYjVPaI 18 | ql2G4zciehjb6b404qlYknhmyM23S+j+uudtz35mRmCcdvrKjWekdwAmLYVO29MU 19 | uXPONDsyIJrR4x7ZmsE/ 20 | -----END PUBLIC KEY----- 21 | -------------------------------------------------------------------------------- /English.lproj/motd.txt: -------------------------------------------------------------------------------- 1 | Syntax highlighting is new in CocoaRestClient! However, it can cause slowness or beachballing when loading very large or complex files; for example, the minified jquery source. If you experience problems, it can be disabled via the menu at View | Syntax Highlighting. 2 | 3 | You won't see this message again. Thanks! 4 | -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | platform :osx, '10.9' 2 | 3 | target 'CocoaRestClient' do 4 | pod 'ACEView', :git => 'https://github.com/mmattozzi/ACEView.git', :submodules => true 5 | pod 'Base64', '~> 1.0' 6 | # pod 'SBJson4', '~> 4.0' 7 | # Use a fork of SBJson that is optimized for pretty printing parsed JSON input 8 | pod 'SBJson', :git => 'https://github.com/mmattozzi/json-framework.git' 9 | pod 'MsgPackSerialization', '~> 0.0.1' 10 | pod 'Sparkle' 11 | pod 'DiffMatchPatch-ObjC', '~> 1.0.0' 12 | end 13 | 14 | target 'CocoaRestClientTests' do 15 | pod 'ACEView', :git => 'https://github.com/mmattozzi/ACEView.git', :submodules => true 16 | end 17 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | About 2 | ================= 3 | CocoaRestClient is a Mac OS X app for testing HTTP/Restful endpoints. 4 | 5 | I love curl, but sometimes I need my output XML or JSON pretty printed. I want to be able to save frequent PUT and POST bodies for later and copy and paste from responses easily. Think of this as curl with a light UI. 6 | 7 | The goal of this project is to build a lightweight native Cocoa app for testing and debugging HTTP Restful services. 8 | This project was greatly inspired by the Java rest-client (https://code.google.com/archive/p/rest-client). 9 | 10 | Official project website: http://mmattozzi.github.io/cocoa-rest-client/ 11 | 12 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmmattozzi%2Fcocoa-rest-client.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmmattozzi%2Fcocoa-rest-client?ref=badge_shield) 13 | 14 | Download 15 | ================= 16 | If you're not looking to compile from source and only want to use this tool, latest releases are here: 17 | 18 | [Download List](https://github.com/mmattozzi/cocoa-rest-client/releases) 19 | 20 | You can also install it through [homebrew](https://brew.sh/) as a [cask](https://caskroom.github.io): 21 | 22 | ```sh 23 | # install cask if necessary 24 | brew tap caskroom/cask 25 | # install CocoaRestClient 26 | brew install --cask cocoarestclient 27 | ``` 28 | 29 | Features 30 | ================= 31 | * Make GET, PUT, POST, DELETE, HEAD calls 32 | * Set request body to arbitrary content 33 | * Set request headers 34 | * Edit URL parameters in an easy to read table 35 | * Set HTTP basic & digest auth 36 | * Auto-format (pretty print) XML, JSON, and MsgPack responses 37 | * Some cool Ace Editor themes for syntax highlighting 38 | * Display response headers 39 | * Quick save requests in a handy sidebar using folder organization 40 | * Upload files and form data via multipart/form-data 41 | * Enter POST/PUT input as raw input or key/value pairs 42 | * Reports response latency 43 | * Command-R reloads last request 44 | * Lightweight: Low real memory usage and < 6mb DMG 45 | * SSL Support (including untrusted certificates) 46 | * Optionally follows HTTP redirects 47 | * Import and export requests 48 | * New in version 1.4: Uses native macOS tabs and windows. 49 | * New in version 1.4.3: Generate a unified diff between two response body tabs 50 | * Supports native MacOS dark mode 51 | * Mac M1/arm and intel processor support 52 | 53 | Screenshots 54 | ================= 55 | 56 | 57 | 58 | *Pretty print JSON content. Set and save HTTP headers.* 59 | 60 | 61 | 62 | *Pretty print XML content. Quick save of request URLs, body, and headers in one convenient drawer.* 63 | 64 | 65 | 66 | *Set HTTP Basic or Digest Auth. Displays HTTP response headers.* 67 | 68 | 69 | 70 | *Upload files using HTTP multipart requests. HTTP form encoding also supported.* 71 | 72 | 73 | 74 | *Unified diff tool for comparing response bodies.* 75 | 76 | Source and Contributions 77 | ================= 78 | * Contributions are always welcome! Please fork and create a pull request. 79 | * Source uses [Cocoapods](https://cocoapods.org/) for dependencies, to get started, [install CocoaPods](http://guides.cocoapods.org/using/getting-started.html) and in the main project directory run: 80 | 81 | ``` 82 | pod install 83 | ``` 84 | * Note that you must have a github account and a public key registered with github so that CocoaPods can pull down a github-hosted dependency. 85 | 86 | Credits 87 | ================= 88 | * Uses a very lightly modified fork of SBJson (https://github.com/SBJson/SBJson) for pretty printing JSON 89 | * Much guidance from Adrian Kosmaczewski blog (http://kosmaczewski.net/playing-with-http-libraries/) 90 | * Sparkle automatic update framework (https://github.com/sparkle-project/Sparkle) 91 | * ACEView syntax highlighting (https://github.com/ACENative/ACEView) 92 | * Base64 encoding uses Matt Gallagher's NSData+Base64 code (http://www.cocoawithlove.com/2009/06/base64-encoding-options-on-mac-and.html) 93 | * Code & testing contributions: Adam Venturella, Sergey Klimov, Cory Alder, Tito Ciuro, Eric Broska, Nicholas Robinson, Diego Massanti, Robert Horvath 94 | 95 | 96 | 97 | ## License 98 | See [LICENSE.txt](https://github.com/mmattozzi/cocoa-rest-client/blob/master/LICENSE.txt) 99 | 100 | [![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fmmattozzi%2Fcocoa-rest-client.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fmmattozzi%2Fcocoa-rest-client?ref=badge_large) 101 | -------------------------------------------------------------------------------- /ReleaseNotes/1.2.2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
    4 |
  • Adding Sparkle update framework
  • 5 |
  • Adding HTTP status phrase
  • 6 |
  • Adding menu link to License text file on web
  • 7 |
8 | 9 | -------------------------------------------------------------------------------- /ReleaseNotes/1.2.3.html: -------------------------------------------------------------------------------- 1 | * Adding SSL support for self-signed certificates (ISSUE-9) 2 | * Adding toggle menu option that allows user to choose whether or not to follow HTTP redirects (ISSUE-8) -------------------------------------------------------------------------------- /ReleaseNotes/1.2.4.html: -------------------------------------------------------------------------------- 1 | * Fix for parsing Content-Type field (ISSUE-10) 2 | * First build on Lion, adding full screen support. Maintains Snow Leopard compatibility. 3 | 4 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.0.html: -------------------------------------------------------------------------------- 1 | * Adding import and export requests. On exports, you will be prompted to select which requests you would like to export. On imports, you will also be prompted to select which requests from the imported file you would like to add to your drawer of requests. This feature can be accessed through the file menu or request can be imported by dragging them into the drawer. 2 | 3 | * Adding sent request headers to the response area. 4 | 5 | * Adding ability to overwrite existing requests in the saved requests drawer by choosing File > Overwrite Request or by pressing Control-Command-S. 6 | 7 | * Adding indefinite progress indicator that runs while requests are in progress. 8 | 9 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.1.html: -------------------------------------------------------------------------------- 1 | New in 1.3.1: 2 | 3 | * Bugfix: correctly decode content served in ISO-8859-1 encoding (such as google.com) 4 | 5 | New in 1.3.0: 6 | 7 | * Adding import and export requests. On exports, you will be prompted to select which requests you would like to export. On imports, you will also be prompted to select which requests from the imported file you would like to add to your drawer of requests. This feature can be accessed through the file menu or request can be imported by dragging them into the drawer. 8 | 9 | * Adding sent request headers to the response area. 10 | 11 | * Adding ability to overwrite existing requests in the saved requests drawer by choosing File > Overwrite Request or by pressing Control-Command-S. 12 | 13 | * Adding indefinite progress indicator that runs while requests are in progress. 14 | 15 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.10.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.10: 2 | 3 | * Fix exporting of requests in folders 4 | * Delete key deletes selected requests in saved requests drawer 5 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.11.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.11: 2 | 3 | * Updated UI for cleaner workspace (less space eaten up by tabs) with adjustable request and response areas (Issue #80, Issue #58) 4 | * Updated Sparkle to latest version and HTTPS URL for appcast (Issue #88) 5 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.12.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.12: 2 | 3 | * Fixes open response in browser 4 | * Puts HTTP Status code back in Headers tab text 5 | * Fixes import of requests 6 | * Adds tabbing between username and password field in Auth tab 7 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.13.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.13: 2 | 3 | * Added Curl command generation, consider this beta for now (Edit Menu or Command-K). 4 | * Fix an issue where a folder drag and drop onto itself causes the folder to get deleted (Issue 100) 5 | * Added a global option to disable cookies (Issue 43) 6 | * DELETEs can now have raw text bodies (Issue 85) 7 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.14.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.14: 2 | 3 | * Fixes bugs in JSON pretty printing that would cause loss of field ordering and loss of number precision for decimal numbers 4 | * Restore support for custom JSON and XML variant Content-Types (where these are content types that have a suffix like "+xml" or "+json" 5 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.15.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.15: 2 | 3 | * Fixes JSON formatting bug that transformed raw numbers into quoted strings (Issue #117) 4 | * Makes some changes to the UI for how to select Raw vs. Field vs. File request types 5 | * Deselects selection from saved requests drawer when naming a saved request so that pressing delete will not remove the saved request that is highlighted (Issue #120) 6 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.16.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.16: 2 | 3 | * Command-T now brings up a typeahead fast searcher of saved requests! 4 | * Tried to standardize request saving behavior with normal MacOS apps: Command-S now saves a request or overwrites a selected request (confirmation box is shown first) and Command-Shift-S works as a 'Save As' to give a request a new name. 5 | * Decreased font size of saved request drawer to make things look a little cleaner 6 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.17.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.17: 2 | 3 | * Added JSON detection for JSON content types that start with 'json+' 4 | * Adding a menu command to reload the saved requests drawer. Useful if anybody is syncing their saved request folder between multiple computers using dropbox or otherwise 5 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.2.html: -------------------------------------------------------------------------------- 1 | New in 1.3.2: 2 | 3 | * Use double click to add a new row to headers, params, or files table. New rows will also be added by pressing TAB at the end of the last row being edited. Backspace key removes rows when selected. 4 | * Added preferences menu to persist update preferences, request timeout settings, and HTTP redirect settings. 5 | * Bugfix (Issue 15): Fixed bug where Content-Type of request can be erroneously repeated for multipart and form encoded requests. 6 | * Bugfix (Issue 17): Automatically URL encode requests to handle non-ASCII characters. I'm amazed it took this long to catch this! 7 | 8 | New in 1.3.1: 9 | 10 | * Bugfix: correctly decode content served in ISO-8859-1 encoding (such as google.com) 11 | 12 | New in 1.3.0: 13 | 14 | * Adding import and export requests. On exports, you will be prompted to select which requests you would like to export. On imports, you will also be prompted to select which requests from the imported file you would like to add to your drawer of requests. This feature can be accessed through the file menu or request can be imported by dragging them into the drawer. 15 | 16 | * Adding sent request headers to the response area. 17 | 18 | * Adding ability to overwrite existing requests in the saved requests drawer by choosing File > Overwrite Request or by pressing Control-Command-S. 19 | 20 | * Adding indefinite progress indicator that runs while requests are in progress. 21 | 22 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.3.html: -------------------------------------------------------------------------------- 1 | New in 1.3.3: 2 | * Added syntax highlighting to raw requests and responses (can be enabled or disabled via menu option) 3 | * Added OPTIONS, PATCH and SEARCH HTTP verbs (ISSUE-18) 4 | * Added menu options to increase or decrease request and response font size 5 | * Added menu option to export response text to file 6 | * Added menu option to open response text in default browser 7 | * Added menu option to open response text in default application 8 | * Added menu option to re-GET request using default browser 9 | * Form encoding bugfix for '&' character (Pull request 7) 10 | * Fix for parsing Content-Type headers that don't contain charsets 11 | 12 | New in 1.3.2: 13 | 14 | * Use double click to add a new row to headers, params, or files table. New rows will also be added by pressing TAB at the end of the last row being edited. Backspace key removes rows when selected. 15 | * Added preferences menu to persist update preferences, request timeout settings, and HTTP redirect settings. 16 | * Bugfix (Issue 15): Fixed bug where Content-Type of request can be erroneously repeated for multipart and form encoded requests. 17 | * Bugfix (Issue 17): Automatically URL encode requests to handle non-ASCII characters. I'm amazed it took this long to catch this! 18 | 19 | New in 1.3.1: 20 | 21 | * Bugfix: correctly decode content served in ISO-8859-1 encoding (such as google.com) 22 | 23 | New in 1.3.0: 24 | 25 | * Adding import and export requests. On exports, you will be prompted to select which requests you would like to export. On imports, you will also be prompted to select which requests from the imported file you would like to add to your drawer of requests. This feature can be accessed through the file menu or request can be imported by dragging them into the drawer. 26 | 27 | * Adding sent request headers to the response area. 28 | 29 | * Adding ability to overwrite existing requests in the saved requests drawer by choosing File > Overwrite Request or by pressing Control-Command-S. 30 | 31 | * Adding indefinite progress indicator that runs while requests are in progress. 32 | 33 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.4.html: -------------------------------------------------------------------------------- 1 | New in 1.3.4: 2 | * Pick more appropriate syntax highlighting based on certain known Content-Types 3 | * Respect the HTTP Method on redirected requests 4 | * Menu item and Command-W added for closing window 5 | 6 | New in 1.3.3: 7 | * Added syntax highlighting to raw requests and responses (can be enabled or disabled via menu option) 8 | * Added OPTIONS, PATCH and SEARCH HTTP verbs (ISSUE-18) 9 | * Added menu options to increase or decrease request and response font size 10 | * Added menu option to export response text to file 11 | * Added menu option to open response text in default browser 12 | * Added menu option to open response text in default application 13 | * Added menu option to re-GET request using default browser 14 | * Form encoding bugfix for '&' character (Pull request 7) 15 | * Fix for parsing Content-Type headers that don't contain charsets 16 | 17 | New in 1.3.2: 18 | 19 | * Use double click to add a new row to headers, params, or files table. New rows will also be added by pressing TAB at the end of the last row being edited. Backspace key removes rows when selected. 20 | * Added preferences menu to persist update preferences, request timeout settings, and HTTP redirect settings. 21 | * Bugfix (Issue 15): Fixed bug where Content-Type of request can be erroneously repeated for multipart and form encoded requests. 22 | * Bugfix (Issue 17): Automatically URL encode requests to handle non-ASCII characters. I'm amazed it took this long to catch this! 23 | 24 | New in 1.3.1: 25 | 26 | * Bugfix: correctly decode content served in ISO-8859-1 encoding (such as google.com) 27 | 28 | New in 1.3.0: 29 | 30 | * Adding import and export requests. On exports, you will be prompted to select which requests you would like to export. On imports, you will also be prompted to select which requests from the imported file you would like to add to your drawer of requests. This feature can be accessed through the file menu or request can be imported by dragging them into the drawer. 31 | 32 | * Adding sent request headers to the response area. 33 | 34 | * Adding ability to overwrite existing requests in the saved requests drawer by choosing File > Overwrite Request or by pressing Control-Command-S. 35 | 36 | * Adding indefinite progress indicator that runs while requests are in progress. 37 | 38 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.5.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.5: 2 | * Add text/json to list of known JSON content types 3 | * For JSON content types that fail to parse, output plaintext instead of hanging 4 | * Apply Same Method on HTTP Redirects menu option. For HTTP 301, 302, & 303s, there is w3c guidance about when the POST should be propogated rather than converted into a GET on the target of the redirect. Some users were not expecting this and (for better or worse) will be able to override the built-in rules and propogate the HTTP method to the target of the redirect no matter what the guidelines are. In the previous version, this erroneously was made the default behavior -- but it is now configurable. (ISSUE-26) 5 | * Clicking dock icon re-opens main window if it is closed 6 | * Gzip checkbox for multipart file uploads 7 | * Drag'n'drop files from Finder to File upload list 8 | * Selectable syntax highlighting for responses 9 | * Auto-complete for common HTTP header field names 10 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.6.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.6: 2 | 3 | * Fixed encoding of the + character for parameters provided for form urlencoded content. 4 | 5 | * Turned off XML tidying-- this was resulting in elements being added where they truly did not exist in the response. Now, if XML is invalid it will default to plaintext in the response window. 6 | 7 | * Changed tabbing behavior in request parameter and header value cells to be more natural. 8 | 9 | * Added pre-emptive HTTP Basic Auth. This can be enabled with a checkbox and hopefully will solve the auth problems that some people have been having. 10 | 11 | * Added MessagePack output formatting (contributed by github.com/DiegoMax) 12 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.7.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.7: 2 | 3 | * Combo box for supplying arbitrary HTTP method replaces drop down box of preset HTTP methods. 4 | 5 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.8.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.8: 2 | 3 | * New syntax highlighting using Ace Editor 4 | * Syntax highlighting themes 5 | * Tree/folder structure for saving requests 6 | * No reordering of JSON keys on pretty printing 7 | * Adds text/plain to Content-Type menu 8 | * Uses ARC for memory management 9 | * Should hopefully fix text box display issues on latest OS X versions >= 10.10 10 | * Fixes bug where requests are only saved on exit 11 | * New icon! 12 | -------------------------------------------------------------------------------- /ReleaseNotes/1.3.9.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.3.9: 2 | * Fixes bug with overwriting existing requests 3 | * When syntax highlighting is turned off, use fixed width font 4 | 5 | Fixes/Features in 1.3.8 (Release 5/4/2015): 6 | 7 | * New syntax highlighting using Ace Editor 8 | * Syntax highlighting themes 9 | * Tree/folder structure for saving requests 10 | * No reordering of JSON keys on pretty printing 11 | * Adds text/plain to Content-Type menu 12 | * Uses ARC for memory management 13 | * Should hopefully fix text box display issues on latest OS X versions >= 10.10 14 | * Fixes bug where requests are only saved on exit 15 | * New icon! 16 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.0.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.0: 2 | 3 | * Multiple windows and tabs using macOS's native tab support! 4 | * Saved requests list is now part of each main window rather than a drawer (the drawer concept seems to be poorly supported in today's macOS libraries). 5 | * New keymappings: Command-N opens a new window, Command-T opens a new tab, and Command-O opens the saved request name searcher. 6 | * Bottom status bar looks slightly classier. 7 | * Enabling or disabling trust of self-signed certs is now a menu option. 8 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.1.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.1: 2 | 3 | * Of course, if you haven't upgraded to 1.4.x yet, be sure to give it a try since 1.4.0+ versions support new windows and tabbed windows using native macOS tabbing support! 4 | 5 | * No longer automatically sets Accept-Encoding and Accept-Language header fields on outgoing requests (Issue #128). 6 | * Fixes pre-emptive auth broken in 1.4.0 (Issue #129) 7 | * Remembers the preferred width of the saved requests sidebar 8 | * Adds a submit request menu item mapped to Control-S (Issue #116) 9 | * Remember last Content-Type header selection from Content-Type menu (Issue #81) 10 | * Increases number of visible HTTP Methods in dropdown (Issue #108) 11 | * Fixes minor bug that causes import and export requests functionality to break after Reload Requests Drawer menu item is invoked. 12 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.2.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.2: 2 | 3 | * Of course, if you haven't upgraded to 1.4.x yet, be sure to give it a try since 1.4.0+ versions support new windows and tabbed windows using native macOS tabbing support! 4 | 5 | * Added an additional table to input URL parameters; synced with changes to the URL bar. (Issue #67, Issue #56) 6 | * If the requst contains the Accept-Encoding header, append --compressed to a generated curl command so that curl decompresses the response body automatically. (Issue #130) 7 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.3.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.3: 2 | 3 | * Of course, if you haven't upgraded to 1.4.x yet, be sure to give it a try since 1.4.0+ versions support new windows and tabbed windows using native macOS tabbing support! 4 | 5 | * Add a tool to produce a unified diff of two responses 6 | * Fixed double clicking and tabbing in tables (Issue #131) 7 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.4.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.4: 2 | 3 | * Issue #135: Fix for bug which caused app to crash while parsing JSON using invalid encoding 4 | * Issue #139: Adding Window menu for managing windows and tabs 5 | 6 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.5.html: -------------------------------------------------------------------------------- 1 | Fixes/Features in 1.4.5: 2 | 3 | * Adding support for Touch Bar: save, open, get, post, put, and copy curl buttons that are always available on touch bar while in the main window of the app. 4 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.6.html: -------------------------------------------------------------------------------- 1 | Fixes/Features/Changes in 1.4.6: 2 | 3 | * Universal binary for M1 (arm64) and Intel (x86) macs 4 | * Minimum supported MacOS version set to 10.14 5 | * Proper dark mode implementation adding MacOS vibrancy effects in background 6 | * Supports saving two different pretty print themes (normal and dark mode) 7 | * Remove double encoding of spaces in URL box (Issue #152) 8 | * Adds environment variable substitution in headers, specified as ${VAR} 9 | * Gatekeeper compatible signed release binary 10 | * Minor UI arrangement tweaks 11 | -------------------------------------------------------------------------------- /ReleaseNotes/1.4.7.html: -------------------------------------------------------------------------------- 1 | Fixes/Features/Changes in 1.4.7: 2 | 3 | * Fixed header and parameter table column widths 4 | -------------------------------------------------------------------------------- /core/CheckableRequestWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // CheckableRequestWrapper.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/15/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CRCSavedRequestFolder.h" 11 | 12 | @interface CheckableRequestWrapper : NSObject { 13 | NSCellStateValue _enabled; 14 | id request; 15 | NSString *name; 16 | NSMutableArray *contents; 17 | CheckableRequestWrapper *parent; 18 | } 19 | 20 | + (CheckableRequestWrapper *) checkableRequestWrapperForRequest: (id)request; 21 | - (CheckableRequestWrapper *) initWithName:(NSString *)name enabled:(BOOL)enabled request:(id)request; 22 | - (NSString *) name; 23 | - (id) request; 24 | - (NSCellStateValue) enabled; 25 | - (void) setEnabled:(BOOL)reqEnabled; 26 | - (int) count; 27 | - (NSMutableArray*) contents; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /core/CheckableRequestWrapper.m: -------------------------------------------------------------------------------- 1 | // 2 | // CheckableRequestWrapper.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/15/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "CheckableRequestWrapper.h" 10 | 11 | @implementation CheckableRequestWrapper 12 | 13 | + (CheckableRequestWrapper *) checkableRequestWrapperForRequest: (id) request { 14 | 15 | NSString* name; 16 | if ([request isKindOfClass:[NSDictionary class]]) { 17 | name = [request objectForKey:@"name"]; 18 | } else { 19 | name = [request name]; 20 | } 21 | 22 | CheckableRequestWrapper *requestWrapper = [[CheckableRequestWrapper alloc] initWithName:name enabled:YES request:request]; 23 | 24 | if ([request isKindOfClass:[CRCSavedRequestFolder class]]) { 25 | CRCSavedRequestFolder *crcFolder = (CRCSavedRequestFolder *) request; 26 | for (id object in [crcFolder contents]) { 27 | CheckableRequestWrapper* child = [CheckableRequestWrapper checkableRequestWrapperForRequest:object]; 28 | child->parent = requestWrapper; 29 | 30 | [[requestWrapper contents] addObject:child]; 31 | } 32 | } 33 | 34 | return requestWrapper; 35 | } 36 | 37 | - (CheckableRequestWrapper *) initWithName:(NSString *)reqName enabled:(BOOL)reqEnabled request:(id)requestObject { 38 | self = [super init]; 39 | 40 | if (self) { 41 | name = reqName; 42 | _enabled = reqEnabled; 43 | request = requestObject; 44 | contents = [NSMutableArray array]; 45 | } 46 | 47 | return self; 48 | } 49 | 50 | - (NSCellStateValue) enabled { 51 | return _enabled; 52 | } 53 | 54 | - (NSString *) name { 55 | return name; 56 | } 57 | 58 | - (id) request { 59 | return request; 60 | } 61 | 62 | - (void) setEnabled:(BOOL)reqEnabled { 63 | _enabled = reqEnabled; 64 | 65 | [self setChildrenEnabled:reqEnabled]; 66 | [self updateParent]; 67 | } 68 | 69 | - (void) setChildrenEnabled:(BOOL)reqEnabled { 70 | for (CheckableRequestWrapper* child in contents) { 71 | child->_enabled = reqEnabled; 72 | [child setChildrenEnabled:reqEnabled]; 73 | } 74 | } 75 | 76 | - (void) updateParent { 77 | if (parent == nil) return; 78 | 79 | int checkedChildren = 0; 80 | for (CheckableRequestWrapper* child in [parent contents]) { 81 | if (child.enabled != NSOffState) checkedChildren++; 82 | } 83 | 84 | NSCellStateValue state; 85 | if (checkedChildren == 0) { 86 | state = NSOffState; 87 | } else if (checkedChildren == [[parent contents] count]) { 88 | state = NSOnState; 89 | } else { 90 | state = NSMixedState; 91 | } 92 | 93 | if ([parent enabled] == state) return; 94 | 95 | parent->_enabled = state; 96 | [parent updateParent]; 97 | } 98 | 99 | - (int) count { 100 | return [contents count]; 101 | } 102 | 103 | - (NSMutableArray*) contents { 104 | return contents; 105 | } 106 | 107 | @end 108 | -------------------------------------------------------------------------------- /core/CocoaRestClientAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // CocoaRestClientAppDelegate.h 3 | // CocoaRestClient 4 | // 5 | // Created by mmattozzi on 1/5/10. 6 | // Copyright 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | #import 11 | #import "ExportRequestsController.h" 12 | #import "CRCDrawerView.h" 13 | #import "TabbingTableView.h" 14 | #import "PreferencesController.h" 15 | #import "WelcomeController.h" 16 | #import "TableRowAndColumn.h" 17 | #import "ACEView/ACEView.h" 18 | #import "HighlightingTypeManager.h" 19 | #import 20 | #import "CRCConstants.h" 21 | #import "DMSlidingTabView.h" 22 | #import "DMSlidingTabItemView.h" 23 | #import "FastSearchSavedRequestsController.h" 24 | #import "DiffWindowController.h" 25 | 26 | @class CRCRequest; 27 | @class CRCDrawerView; 28 | @class MainWindowController; 29 | @class SavedRequestsDataSource; 30 | 31 | @interface CocoaRestClientAppDelegate : NSObject { 32 | ExportRequestsController *exportRequestsController; 33 | PreferencesController *preferencesController; 34 | FastSearchSavedRequestsController *fastSearchSavedRequestsController; 35 | DiffWindowController *diffWindowController; 36 | 37 | MainWindowController *currentWindowController; 38 | 39 | id eventMonitor; 40 | id lastSelectedSavedOutlineViewItem; 41 | NSUInteger windowNumber; 42 | } 43 | 44 | // Reference to WindowControllers of all windows that are open 45 | @property (retain) NSMutableArray *mainWindowControllers; 46 | 47 | // Manages saved request outline view data across all windows 48 | @property (strong) SavedRequestsDataSource *savedRequestsDataSource; 49 | 50 | // Used throughout by all application windows 51 | @property (strong) NSSet *requestMethodsWithoutBody; 52 | @property (atomic) NSUInteger aceViewFontSize; 53 | 54 | // Menu Items that need to be checked, unchecked, enabled, or disabled 55 | @property (weak) IBOutlet NSMenuItem *syntaxHighlightingMenuItem; 56 | @property (weak) IBOutlet NSMenuItem *reGetResponseMenuItem; 57 | @property (weak) IBOutlet NSMenuItem *showLineNumbersMenuItem; 58 | @property (weak) IBOutlet NSMenuItem *themeMenuItem; 59 | @property (weak) IBOutlet NSMenuItem *showSavedRequestsMenuItem; 60 | 61 | // Window management methods 62 | - (void) addTabFromWindow:(NSWindow *)window; 63 | - (void) tabWasRemoved:(NSWindowController *)windowController; 64 | - (void) setCurrentMainWindowController:(MainWindowController *)mainWindowController; 65 | - (void) applicationWillTerminate: (NSNotification *)note; 66 | - (void) windowSubmittedRequest:(MainWindowController *)mainWindowController; 67 | - (void) setWindowTitle:(MainWindowController *)mainWindowController withBaseTitle:(NSString *)title; 68 | - (void) setWindowTitle:(MainWindowController *)mainWindowController withBaseTitle:(NSString *)title index:(NSUInteger)index; 69 | 70 | // Saved requests management 71 | - (void) redrawRequestViews; 72 | - (void) deselectSavedRequest:(NSNotification *)notification; 73 | - (void) importRequestsFromArray:(NSArray *)requests; 74 | - (void) deleteSavedRequest: (NSNotification *) notification; 75 | 76 | // Utility Methods 77 | - (void) invalidFileAlert; 78 | - (IBAction) restartRequiredAlert:(id)sender; 79 | - (NSString *) saveResponseToTempFile; 80 | + (NSString *) nameForRequest:(id)object; 81 | + (void) addBorderToView:(NSView *)view; 82 | 83 | // 84 | // Actions driven from Menu Items 85 | // 86 | 87 | /* Application Menu */ 88 | - (IBAction)showPreferences:(id)sender; 89 | 90 | /* File Menu */ 91 | - (IBAction) handleOpenWindow:(id)sender; 92 | - (IBAction) handleCloseWindow:(id)sender; 93 | - (IBAction) newTab:(id)sender; 94 | - (IBAction) submitRequest:(id)sender; 95 | - (IBAction) reloadLastRequest:(id)sender; 96 | - (IBAction) overwriteRequest:(id) sender; // Save 97 | - (IBAction) saveRequest:(id) sender; // Save As... 98 | - (IBAction) deleteSavedRequestFromMenu:(id) sender; 99 | - (IBAction) importRequests:(id)sender; 100 | - (IBAction) exportRequests:(id)sender; 101 | - (IBAction) reloadRequestsDrawer:(id)sender; 102 | - (IBAction) exportResponse:(id)sender; 103 | - (IBAction) viewResponseInBrowser:(id)sender; 104 | - (IBAction) viewResponseInDefaultApplication:(id)sender; 105 | - (IBAction) reGetResponseInBrowser:(id)sender; 106 | 107 | /* Edit Menu */ 108 | - (IBAction) copyCurlCommand:(id)sender; 109 | - (IBAction) findMenuItem:(id)sender; 110 | - (IBAction) replaceMenuItem:(id)sender; 111 | - (IBAction) findNextMenuItem:(id)sender; 112 | - (IBAction) findPreviousMenuItem:(id)sender; 113 | 114 | /* Options Menu */ 115 | - (IBAction) openTimeoutDialog:(id) sender; 116 | // Rest of Option MenuItems just set SharedUserDefaults in IB 117 | 118 | /* View Menu */ 119 | - (IBAction) toggleVerticalSplitView:(id)sender; 120 | - (IBAction) syntaxHighlightingToggled:(id)sender; 121 | - (IBAction) showLineNumbersToggled:(id)sender; 122 | - (IBAction) openFastSearchSavedRequestsPanel:(id)sender; 123 | - (IBAction) zoomDefault:(id)sender; 124 | - (IBAction) zoomIn:(id)sender; 125 | - (IBAction) zoomOut:(id)sender; 126 | - (IBAction) themeMenuItemSelected:(id)sender; 127 | - (IBAction) diffTwoResponses:(id)sender; 128 | 129 | /* Content Type Menu */ 130 | - (IBAction) contentTypeMenuItemSelected:(id)sender; 131 | 132 | /* Help Menu */ 133 | - (IBAction) helpInfo:(id)sender; 134 | - (IBAction) licenseInfo:(id)sender; 135 | 136 | // Called for all menu enabled/disabled status 137 | - (BOOL)validateMenuItem:(NSMenuItem *)item; 138 | 139 | @end 140 | -------------------------------------------------------------------------------- /core/CocoaRestClient_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'CocoaRestClient' target in the 'CocoaRestClient' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | 9 | #ifndef DEBUG 10 | #define NSLog(...) 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /core/ContentTypes.h: -------------------------------------------------------------------------------- 1 | // 2 | // ContentTypes.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 5/29/16. 6 | // Copyright (c) 2016 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ContentTypes : NSObject { 12 | NSArray *xmlContentTypes; 13 | NSArray *jsonContentTypes; 14 | NSArray *msgPackContentTypes; 15 | } 16 | 17 | @property (nonatomic, retain) NSArray *xmlContentTypes; 18 | @property (nonatomic, retain) NSArray *jsonContentTypes; 19 | @property (nonatomic, retain) NSArray *msgPackContentTypes; 20 | 21 | + (ContentTypes *) sharedContentTypes; 22 | 23 | - (BOOL) isXml:(NSString *)contentType; 24 | - (BOOL) isJson:(NSString *)contentType; 25 | - (BOOL) isMsgPack:(NSString *)contentType; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /core/ContentTypes.m: -------------------------------------------------------------------------------- 1 | // 2 | // ContentTypes.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 5/29/16. 6 | // Copyright (c) 2016 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "ContentTypes.h" 10 | 11 | @implementation ContentTypes 12 | 13 | @synthesize xmlContentTypes; 14 | @synthesize jsonContentTypes; 15 | @synthesize msgPackContentTypes; 16 | 17 | + (ContentTypes *) sharedContentTypes { 18 | static ContentTypes *sharedObj = nil; 19 | @synchronized(self) { 20 | if (sharedObj == nil) { 21 | sharedObj = [[self alloc] init]; 22 | 23 | sharedObj.xmlContentTypes = [NSArray arrayWithObjects:@"application/xml", @"application/atom+xml", @"application/rss+xml", 24 | @"text/xml", @"application/soap+xml", @"application/xml-dtd", nil]; 25 | 26 | sharedObj.jsonContentTypes = [NSArray arrayWithObjects:@"application/json", @"text/json", nil]; 27 | 28 | sharedObj.msgPackContentTypes = [NSArray arrayWithObjects:@"application/x-msgpack", @"application/x-messagepack", nil]; 29 | } 30 | } 31 | return sharedObj; 32 | } 33 | 34 | - (BOOL) isXml:(NSString *)contentType { 35 | return ([xmlContentTypes containsObject:contentType] || 36 | ([contentType hasPrefix:@"application"] && [contentType hasSuffix:@"+xml"])); 37 | } 38 | 39 | - (BOOL) isJson:(NSString *)contentType { 40 | return [jsonContentTypes containsObject:contentType] || 41 | ([contentType hasPrefix:@"application"] && [contentType hasSuffix:@"+json"]) || 42 | ([contentType containsString:@"/json+"]); 43 | } 44 | 45 | - (BOOL) isMsgPack:(NSString *)contentType { 46 | return [msgPackContentTypes containsObject:contentType]; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /core/DiffWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // DiffWindowController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 9/14/17. 6 | // 7 | // 8 | 9 | #import 10 | #import 11 | 12 | @class MainWindowController; 13 | 14 | @interface DiffWindowController : NSWindowController 15 | 16 | @property (weak) IBOutlet NSPopUpButton *diffSourceLeft; 17 | @property (weak) IBOutlet NSPopUpButton *diffSourceRight; 18 | @property (weak) IBOutlet WKWebView *diffView; 19 | @property (weak) NSArray * windows; 20 | 21 | - (void) setup:(NSArray *)openWindows; 22 | - (IBAction) updateDiff:(id)sender; 23 | - (IBAction) clearDiff:(id)sender; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /core/DiffWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // DiffWindowController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 9/14/17. 6 | // 7 | // 8 | 9 | #import "DiffWindowController.h" 10 | #import "MainWindowController.h" 11 | #import "DiffMatchPatch.h" 12 | 13 | #define DIFF_STYLE @"" 14 | 15 | @implementation DiffWindowController 16 | 17 | @synthesize diffSourceLeft; 18 | @synthesize diffSourceRight; 19 | @synthesize diffView; 20 | 21 | - (void)windowDidLoad { 22 | [super windowDidLoad]; 23 | 24 | diffView.layer.borderColor = [NSColor grayColor].CGColor; 25 | diffView.layer.borderWidth = 1.0f; 26 | } 27 | 28 | - (void) setup:(NSArray *)openWindows { 29 | NSLog(@"Setting up diff window"); 30 | self.windows = openWindows; 31 | [diffSourceLeft removeAllItems]; 32 | [diffSourceRight removeAllItems]; 33 | for (MainWindowController* window in openWindows) { 34 | [diffSourceLeft addItemWithTitle:window.window.title]; 35 | [diffSourceRight addItemWithTitle:window.window.title]; 36 | } 37 | [self clearDiff:nil]; 38 | } 39 | 40 | - (IBAction) clearDiff:(id)sender { 41 | [self.diffView loadHTMLString:@"" baseURL:nil]; 42 | } 43 | 44 | - (IBAction) updateDiff:(id)sender { 45 | NSInteger leftIndex = [diffSourceLeft indexOfSelectedItem]; 46 | NSInteger rightIndex = [diffSourceRight indexOfSelectedItem]; 47 | NSString* leftIndexResponseText = [[self.windows objectAtIndex:leftIndex] getResponseText]; 48 | if (! leftIndexResponseText) { 49 | [self.diffView loadHTMLString:@"Left index has no response text." baseURL:nil]; 50 | } else { 51 | NSString* rightIndexResponseText = [[self.windows objectAtIndex:rightIndex] getResponseText]; 52 | if (! rightIndexResponseText) { 53 | [self.diffView loadHTMLString:@"Right index has no response text." baseURL:nil]; 54 | } else { 55 | NSArray *diffs = diff_diffsBetweenTextsWithOptions(leftIndexResponseText, rightIndexResponseText, YES, 0.0); 56 | NSString *htmlDiff = diff_prettyHTMLFromDiffs(diffs); 57 | [self.diffView loadHTMLString:[NSString stringWithFormat:@"%@%@", DIFF_STYLE, htmlDiff] baseURL:nil]; 58 | } 59 | } 60 | } 61 | 62 | @end 63 | -------------------------------------------------------------------------------- /core/ExportRequestsController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExportRequestsDelegate.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/15/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ExportRequestsController : NSWindowController { 12 | NSMutableArray *savedRequestsArray; 13 | NSMutableArray *requestsTableModel; 14 | NSTableView *tableView; 15 | 16 | NSButton *importButton; 17 | NSButton *exportButton; 18 | NSButton *allButton; 19 | NSTextField *label; 20 | BOOL isExportsWindow; 21 | } 22 | 23 | @property (strong, atomic) NSMutableArray *savedRequestsArray; 24 | @property (weak, nullable) IBOutlet NSWindow *parent; 25 | 26 | @property (strong) IBOutlet NSTableView *tableView; 27 | @property (strong) IBOutlet NSButton *importButton; 28 | @property (strong) IBOutlet NSButton *exportButton; 29 | @property (strong) IBOutlet NSButton *allButton; 30 | @property (strong) IBOutlet NSTextField *label; 31 | 32 | - (void) prepareToDisplayExports; 33 | - (void) prepareToDisplayImports:(NSArray *)importRequests; 34 | - (IBAction) confirmExport:(id)sender; 35 | - (IBAction) cancelExport:(id)sender; 36 | - (IBAction) clickedAllCheckbox:(id)sender; 37 | - (IBAction) confirmImport:(id)sender; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /core/ExportRequestsController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExportRequestsDelegate.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/15/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "ExportRequestsController.h" 10 | #import "CRCRequest.h" 11 | #import "CRCSavedRequestFolder.h" 12 | #import "CheckableRequestWrapper.h" 13 | 14 | @implementation ExportRequestsController 15 | 16 | @synthesize savedRequestsArray; 17 | @synthesize tableView; 18 | @synthesize importButton; 19 | @synthesize exportButton; 20 | @synthesize allButton; 21 | @synthesize label; 22 | @synthesize parent; 23 | 24 | - (id)initWithWindow:(NSWindow *)awindow { 25 | self = [super initWithWindow:awindow]; 26 | if (self) { 27 | requestsTableModel = [[NSMutableArray alloc] init]; 28 | isExportsWindow = YES; 29 | } 30 | 31 | return self; 32 | } 33 | 34 | - (void) setupWindow { 35 | if (isExportsWindow) { 36 | [importButton setHidden:YES]; 37 | [exportButton setHidden:NO]; 38 | [[self window] setTitle:@"Export Requests"]; 39 | [label setStringValue:@"Select Requests to Export:"]; 40 | } else { 41 | [importButton setHidden:NO]; 42 | [exportButton setHidden:YES]; 43 | [[self window] setTitle:@"Import Requests"]; 44 | [label setStringValue:@"Select Requests to Import:"]; 45 | } 46 | [allButton setState:NSOnState]; 47 | } 48 | 49 | - (void)windowDidLoad { 50 | [super windowDidLoad]; 51 | 52 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 53 | [self setupWindow]; 54 | } 55 | 56 | - (IBAction) confirmExport:(id)sender { 57 | NSLog(@"Pressed export"); 58 | 59 | NSSavePanel* picker = [NSSavePanel savePanel]; 60 | 61 | if ([picker runModal] != NSModalResponseOK) return; 62 | 63 | NSString* path = [[picker URL] path]; 64 | NSLog(@"Saving requests to %@", path); 65 | 66 | NSMutableArray *requestsToExport = [self selectedRequests]; 67 | if ([requestsToExport count] > 0) { 68 | [NSKeyedArchiver archiveRootObject:requestsToExport toFile:path]; 69 | } 70 | 71 | [parent endSheet:[self window] returnCode:NSModalResponseOK]; 72 | } 73 | 74 | - (NSMutableArray *) selectedRequests { 75 | return [self buildRequestsFromWrappers:requestsTableModel]; 76 | } 77 | 78 | - (NSMutableArray *) buildRequestsFromWrappers: (NSMutableArray *)wrappedRequests { 79 | NSMutableArray *requests = [[NSMutableArray alloc] init]; 80 | 81 | for (CheckableRequestWrapper* wrappedRequest in wrappedRequests) { 82 | if ([wrappedRequest enabled] == NSOffState) continue; 83 | 84 | if ([[wrappedRequest request] isKindOfClass:[CRCSavedRequestFolder class]]) { 85 | // build new folder with only selected requests 86 | CRCSavedRequestFolder *request = [[CRCSavedRequestFolder alloc] init]; 87 | request.name = [wrappedRequest name]; 88 | request.contents = [self buildRequestsFromWrappers:[wrappedRequest contents]]; 89 | [requests addObject:request]; 90 | } else if ([wrappedRequest enabled] == NSOnState) { 91 | [requests addObject:[wrappedRequest request]]; 92 | } 93 | } 94 | 95 | return requests; 96 | } 97 | 98 | - (IBAction) confirmImport:(id)sender { 99 | NSLog(@"Pressed import"); 100 | 101 | for (id request in [self selectedRequests]) { 102 | [savedRequestsArray addObject:request]; 103 | } 104 | 105 | [parent endSheet:[self window] returnCode:NSModalResponseOK]; 106 | } 107 | 108 | - (IBAction) cancelExport:(id)sender { 109 | [parent endSheet:[self window] returnCode:NSModalResponseCancel]; 110 | } 111 | 112 | - (void)didEndSheet:(NSWindow *)sheet returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo { 113 | [sheet orderOut:self]; 114 | } 115 | 116 | - (void) prepareToDisplayExports { 117 | isExportsWindow = YES; 118 | [self setupWindow]; 119 | 120 | [requestsTableModel removeAllObjects]; 121 | 122 | for (id object in savedRequestsArray) { 123 | [requestsTableModel addObject:[CheckableRequestWrapper checkableRequestWrapperForRequest:object]]; 124 | } 125 | 126 | [tableView reloadData]; 127 | } 128 | 129 | - (void) prepareToDisplayImports:(NSArray *)importRequests { 130 | isExportsWindow = NO; 131 | [self setupWindow]; 132 | 133 | [requestsTableModel removeAllObjects]; 134 | 135 | for (id object in importRequests) { 136 | [requestsTableModel addObject:[CheckableRequestWrapper checkableRequestWrapperForRequest:object]]; 137 | } 138 | 139 | [tableView reloadData]; 140 | } 141 | 142 | - (IBAction) clickedAllCheckbox:(id)sender { 143 | if ([allButton state] == NSMixedState) { 144 | [allButton setNextState]; 145 | } 146 | 147 | if ([allButton state] == NSOnState) { 148 | for (id object in requestsTableModel) { 149 | CheckableRequestWrapper *req = (CheckableRequestWrapper *) object; 150 | [req setEnabled:YES]; 151 | } 152 | } else { 153 | for (id object in requestsTableModel) { 154 | CheckableRequestWrapper *req = (CheckableRequestWrapper *) object; 155 | [req setEnabled:NO]; 156 | } 157 | } 158 | 159 | [tableView reloadData]; 160 | } 161 | 162 | - (void) updateAllCheckbox { 163 | int checkedRequests = 0; 164 | for (CheckableRequestWrapper* requestWrapper in requestsTableModel) { 165 | if ([requestWrapper enabled] == NSMixedState) { 166 | [allButton setState:NSMixedState]; 167 | return; 168 | } 169 | 170 | if ([requestWrapper enabled] != NSOffState) checkedRequests++; 171 | } 172 | 173 | if (checkedRequests == [requestsTableModel count]) { 174 | [allButton setState: NSOnState]; 175 | } else if (checkedRequests == 0) { 176 | [allButton setState: NSOffState]; 177 | } else { 178 | [allButton setState: NSMixedState]; 179 | } 180 | } 181 | 182 | #pragma mark Outline view methods 183 | - (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(nullable id)item { 184 | if (item != nil) { 185 | CheckableRequestWrapper *requestWrapper = (CheckableRequestWrapper*) item; 186 | return [requestWrapper count]; 187 | } 188 | 189 | return [requestsTableModel count]; 190 | } 191 | 192 | - (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(nullable id)item { 193 | if (item != nil) { 194 | CheckableRequestWrapper *requestWrapper = (CheckableRequestWrapper*) item; 195 | return [[requestWrapper contents] objectAtIndex:index]; 196 | } 197 | 198 | return [requestsTableModel objectAtIndex:index]; 199 | } 200 | 201 | - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { 202 | CheckableRequestWrapper *requestWrapper = (CheckableRequestWrapper*) item; 203 | return [requestWrapper count] > 0; 204 | } 205 | 206 | - (nullable id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(nullable NSTableColumn *)tableColumn byItem:(nullable id)item { 207 | CheckableRequestWrapper *requestWrapper = (CheckableRequestWrapper*) item; 208 | return [NSNumber numberWithInt:[requestWrapper enabled]]; 209 | } 210 | 211 | - (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item { 212 | [cell setTitle: [item name]]; 213 | } 214 | 215 | - (void)outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { 216 | [item setEnabled: [object boolValue]]; 217 | [tableView reloadData]; 218 | [self updateAllCheckbox]; 219 | } 220 | 221 | @end 222 | -------------------------------------------------------------------------------- /core/FastSearchSavedRequestsController.h: -------------------------------------------------------------------------------- 1 | // 2 | // FastSearchSavedRequestsController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 12/29/16. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface FastSearchSavedRequestsController : NSWindowController { 12 | NSMutableArray *requests; 13 | NSArray *baseRequests; 14 | } 15 | 16 | @property (weak) IBOutlet NSTableView *fastSearchRequestsTableView; 17 | @property (weak) IBOutlet NSTextField *fastSearchRequestsTextField; 18 | @property (weak) IBOutlet NSPanel *fastSearchRequestsPanel; 19 | @property (weak) NSWindow *parent; 20 | @property (strong) id selectedRequest; 21 | @property (weak) IBOutlet NSScrollView *requestScrollView; 22 | 23 | - (void) setupWindow:(NSArray *)requests; 24 | - (void) sendDeleteKey; 25 | - (IBAction) doubleClickOnTable:(id)sender; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /core/FastSearchSavedRequestsController.m: -------------------------------------------------------------------------------- 1 | // 2 | // FastSearchSavedRequestsController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 12/29/16. 6 | // 7 | // 8 | 9 | #import "FastSearchSavedRequestsController.h" 10 | #import "CRCRequest.h" 11 | #import "CRCSavedRequestFolder.h" 12 | #import "SelectableSavedRequestWrapper.h" 13 | #import "FastSearchSavedRequestTextCellView.h" 14 | 15 | @interface FastSearchSavedRequestsController () 16 | 17 | @end 18 | 19 | @implementation FastSearchSavedRequestsController 20 | 21 | @synthesize fastSearchRequestsPanel; 22 | @synthesize fastSearchRequestsTableView; 23 | @synthesize fastSearchRequestsTextField; 24 | @synthesize parent; 25 | @synthesize selectedRequest; 26 | @synthesize requestScrollView; 27 | 28 | - (id)initWithWindow:(NSWindow *)awindow { 29 | self = [super initWithWindow:awindow]; 30 | if (self) { 31 | requests = [[NSMutableArray alloc] init]; 32 | } 33 | 34 | return self; 35 | } 36 | 37 | - (void)windowDidLoad { 38 | [super windowDidLoad]; 39 | [fastSearchRequestsTableView setAllowsTypeSelect:NO]; 40 | 41 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 42 | [self setupWindow:nil]; 43 | } 44 | 45 | - (void) setupWindow:(NSArray *)savedRequestsArray { 46 | NSIndexSet *indexSet = [NSIndexSet indexSetWithIndex:0]; 47 | [fastSearchRequestsTableView selectRowIndexes:indexSet byExtendingSelection:NO]; 48 | 49 | [fastSearchRequestsTextField setStringValue:@""]; 50 | 51 | if (savedRequestsArray) { 52 | baseRequests = savedRequestsArray; 53 | [self refreshRequestList]; 54 | } 55 | 56 | [self.window makeFirstResponder:fastSearchRequestsTextField]; 57 | } 58 | 59 | - (void) refreshRequestList { 60 | [requests removeAllObjects]; 61 | [self addSavedRequests:nil path:@"/"]; 62 | [self.fastSearchRequestsTableView reloadData]; 63 | [self resetScrolling]; 64 | } 65 | 66 | - (void) addSavedRequests:(NSArray *)savedRequestsArray path:(NSString *)path { 67 | if (! savedRequestsArray) { 68 | savedRequestsArray = baseRequests; 69 | } 70 | NSString *currentSearchString = [fastSearchRequestsTextField stringValue]; 71 | for (id req in savedRequestsArray) { 72 | if([req isKindOfClass:[CRCRequest class]]) { 73 | if (([currentSearchString length] == 0) || [[req name] rangeOfString:currentSearchString options:NSCaseInsensitiveSearch].location != NSNotFound) { 74 | [requests addObject:[SelectableSavedRequestWrapper initWithRequest:req withPath:path]]; 75 | } 76 | } else if ([req isKindOfClass:[CRCSavedRequestFolder class]]) { 77 | NSString* buildPath = [NSString stringWithFormat:@"%@%@/", path, [req name]]; 78 | [self addSavedRequests:[((CRCSavedRequestFolder *) req) contents] path:buildPath]; 79 | } 80 | } 81 | } 82 | 83 | - (void)cancelOperation:(nullable id)sender { 84 | [parent endSheet:self.window returnCode:NSModalResponseCancel]; 85 | } 86 | 87 | - (void) pickedRow { 88 | NSInteger selectedRow = [fastSearchRequestsTableView selectedRow]; 89 | if (selectedRow > -1) { 90 | SelectableSavedRequestWrapper *wrapper = [requests objectAtIndex:selectedRow]; 91 | self.selectedRequest = wrapper.request; 92 | [parent endSheet:self.window returnCode:NSModalResponseOK]; 93 | } 94 | } 95 | 96 | - (void)characterTypedInTable:(NSEvent *)theEvent { 97 | NSString *characterTyped = [theEvent charactersIgnoringModifiers]; 98 | [fastSearchRequestsTextField setStringValue:[NSString stringWithFormat:@"%@%@", [fastSearchRequestsTextField stringValue], characterTyped]]; 99 | [self.window makeFirstResponder:fastSearchRequestsTextField]; 100 | 101 | [fastSearchRequestsTextField performKeyEquivalent:theEvent]; 102 | [self deselectText]; 103 | [self controlTextDidChange:[NSNotification notificationWithName:@"TextChanged" object:fastSearchRequestsTextField]]; 104 | } 105 | 106 | - (void)keyDown:(NSEvent *)theEvent { 107 | if ([theEvent keyCode] == 36) { 108 | // Return 109 | [self pickedRow]; 110 | } else if ([theEvent keyCode] == 51) { 111 | // Backspace 112 | NSString *val = [fastSearchRequestsTextField stringValue]; 113 | [fastSearchRequestsTextField setStringValue:[val substringToIndex:([val length] - 1)]]; 114 | [self.window makeFirstResponder:fastSearchRequestsTextField]; 115 | [self deselectText]; 116 | [self controlTextDidChange:[NSNotification notificationWithName:@"TextChanged" object:fastSearchRequestsTextField]]; 117 | } else { 118 | [self characterTypedInTable:theEvent]; 119 | } 120 | } 121 | 122 | /** Handle strange case where type select swallows spacebar event, even if type select is disabled. */ 123 | - (BOOL)tableView:(NSTableView *)tableView shouldTypeSelectForEvent:(NSEvent *)event withCurrentSearchString:(NSString *)searchString { 124 | if ([event.charactersIgnoringModifiers characterAtIndex:0] == 0x20) { 125 | [self.window makeFirstResponder:fastSearchRequestsTextField]; 126 | } 127 | return NO; 128 | } 129 | 130 | - (IBAction)doubleClickOnTable:(id)sender { 131 | [self pickedRow]; 132 | } 133 | 134 | - (void)sendDeleteKey { 135 | [fastSearchRequestsTextField setStringValue:[[fastSearchRequestsTextField stringValue] substringToIndex:[[fastSearchRequestsTextField stringValue] length] - 1]]; 136 | [self.window makeFirstResponder:fastSearchRequestsTextField]; 137 | [self deselectText]; 138 | } 139 | 140 | - (void)deselectText { 141 | NSRange tRange = [[fastSearchRequestsTextField currentEditor] selectedRange]; 142 | [[fastSearchRequestsTextField currentEditor] setSelectedRange:NSMakeRange(tRange.length,0)]; 143 | } 144 | 145 | - (void)resetScrolling { 146 | // Scroll the vertical scroller to top 147 | if ([requestScrollView hasVerticalScroller]) { 148 | requestScrollView.verticalScroller.floatValue = 0; 149 | } 150 | 151 | // Scroll the content back to the top 152 | [requestScrollView.contentView scrollToPoint:NSMakePoint(0, 0)]; 153 | } 154 | 155 | - (BOOL)control:(NSControl *)control textView:(NSTextView *)fieldEditor 156 | doCommandBySelector:(SEL)commandSelector { 157 | if( commandSelector == @selector(moveUp:) ){ 158 | if ([requests count] > 0) { 159 | [self.window makeFirstResponder:fastSearchRequestsTableView]; 160 | return YES; 161 | } 162 | } 163 | if( commandSelector == @selector(moveDown:) ){ 164 | if ([requests count] > 0) { 165 | [self.window makeFirstResponder:fastSearchRequestsTableView]; 166 | if ([fastSearchRequestsTableView selectedRow] == -1) { 167 | [fastSearchRequestsTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:0] byExtendingSelection:NO]; 168 | } 169 | return YES; 170 | } 171 | } 172 | 173 | return NO; 174 | } 175 | 176 | - (void)controlTextDidChange:(NSNotification *)notification { 177 | [self refreshRequestList]; 178 | } 179 | 180 | - (NSInteger) numberOfRowsInTableView:(NSTableView *) tableView { 181 | return [requests count]; 182 | } 183 | 184 | - (NSView *)tableView:(NSTableView *)tableView viewForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row { 185 | FastSearchSavedRequestTextCellView *result = [tableView makeViewWithIdentifier:tableColumn.identifier owner:self]; 186 | SelectableSavedRequestWrapper *wrapper = (SelectableSavedRequestWrapper *)[requests objectAtIndex:row]; 187 | // result.imageView.image = item.itemIcon; 188 | result.textField.stringValue = wrapper.request.name; 189 | result.detailTextField.stringValue = wrapper.path; 190 | return result; 191 | } 192 | 193 | @end 194 | -------------------------------------------------------------------------------- /core/MainWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // MainWindowController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/7/17. 6 | // 7 | // 8 | 9 | #import 10 | #import "ExportRequestsController.h" 11 | #import "TabbingTableView.h" 12 | #import "PreferencesController.h" 13 | #import "WelcomeController.h" 14 | #import "TableRowAndColumn.h" 15 | #import "ACEView/ACEView.h" 16 | #import "HighlightingTypeManager.h" 17 | #import 18 | #import "CRCConstants.h" 19 | #import "DMSlidingTabView.h" 20 | #import "DMSlidingTabItemView.h" 21 | #import "CRCRequest.h" 22 | #import "ACEView+TouchBarExtension.h" 23 | 24 | @class CocoaRestClientAppDelegate; 25 | @class SavedRequestsDataSource; 26 | @class CRCDrawerView; 27 | 28 | @interface MainWindowController : NSWindowController { 29 | 30 | NSMutableData *receivedData; 31 | NSString *contentType; 32 | NSString *charset; 33 | NSURLRequest *currentRequest; 34 | NSDate *startDate; 35 | 36 | @private NSTouchBarCustomizationIdentifier touchBarIdentifier; 37 | @private NSTouchBarItemIdentifier touchBarSaveIdentifier; 38 | @private NSTouchBarItemIdentifier touchBarSaveAsIdentifier; 39 | @private NSTouchBarItemIdentifier touchBarOpenIdentifier; 40 | @private NSTouchBarItemIdentifier touchBarGetIdentifier; 41 | @private NSTouchBarItemIdentifier touchBarPostIdentifier; 42 | @private NSTouchBarItemIdentifier touchBarPutIdentifier; 43 | @private NSTouchBarItemIdentifier touchBarCopyCurlIdentifier; 44 | @private NSDictionary *touchBarIdentifierToItemMap; 45 | 46 | @private HighlightingTypeManager *responseTypeManager; 47 | @private HighlightingTypeManager *requestTypeManager; 48 | @private SBJson4Writer *jsonWriter; 49 | } 50 | 51 | // Ties to parent application 52 | @property (weak) CocoaRestClientAppDelegate *appDelegate; 53 | @property (weak) IBOutlet SavedRequestsDataSource *savedRequestsDataSource; 54 | 55 | // Configuration of current request 56 | @property (nonatomic) NSMutableArray *headersTable; 57 | @property (nonatomic) NSMutableArray *filesTable; 58 | @property (nonatomic) NSMutableArray *paramsTable; 59 | @property (nonatomic) NSMutableArray *urlParamsTable; 60 | @property (nonatomic) BOOL preemptiveBasicAuth; 61 | @property (nonatomic) BOOL rawRequestBody; 62 | @property (nonatomic) BOOL fileRequestBody; 63 | 64 | // Maintain last request after each execution 65 | @property (retain) CRCRequest *lastRequest; 66 | 67 | // Request Outlets 68 | @property (weak) IBOutlet NSComboBox *urlBox; 69 | @property IBOutlet DMSlidingTabView *requestTabView; 70 | @property IBOutlet DMSlidingTabItemView *requestBodyItemView; 71 | @property IBOutlet DMSlidingTabItemView *requestAuthItemView; 72 | @property IBOutlet DMSlidingTabItemView *requestFilesItemView; 73 | @property IBOutlet DMSlidingTabItemView *requestHeadersItemView; 74 | @property IBOutlet DMSlidingTabItemView *urlParametersItemView; 75 | @property (weak) IBOutlet ACEView *requestView; 76 | @property (weak) IBOutlet NSComboBox *methodButton; 77 | @property (weak) IBOutlet TabbingTableView *headersTableView; 78 | @property (weak) IBOutlet TabbingTableView *filesTableView; 79 | @property (weak) IBOutlet TabbingTableView *paramsTableView; 80 | @property (weak) IBOutlet TabbingTableView *urlParametersTableView; 81 | @property (weak) IBOutlet NSTextField *username; 82 | @property (weak) IBOutlet NSTextField *password; 83 | @property (weak) IBOutlet NSButton *plusParam; 84 | @property (weak) IBOutlet NSButton *minusParam; 85 | @property (weak) IBOutlet NSButton *submitButton; 86 | @property (unsafe_unretained) IBOutlet NSTextView *requestTextPlain; 87 | @property (weak) IBOutlet NSScrollView *requestTextPlainView; 88 | @property (weak) IBOutlet NSButton *rawInputButton; 89 | @property (weak) IBOutlet NSButton *fieldInputButton; 90 | @property (weak) IBOutlet NSButton *fileInputButton; 91 | @property (weak) IBOutlet NSButton *plusUrlParameterButton; 92 | @property (weak) IBOutlet NSButton *minusUrlParameterButton; 93 | @property (weak) IBOutlet NSVisualEffectView *mainBodyView; 94 | @property (weak) IBOutlet NSVisualEffectView *topOuterView; 95 | 96 | // Response Outlets 97 | @property IBOutlet DMSlidingTabView *responseTabView; 98 | @property IBOutlet DMSlidingTabItemView *responseBodyItemView; 99 | @property IBOutlet DMSlidingTabItemView *responseHeadersItemView; 100 | @property IBOutlet DMSlidingTabItemView *responseHeadersSentItemView; 101 | @property (unsafe_unretained) IBOutlet NSTextView *responseTextHeaders; 102 | @property (weak) IBOutlet ACEView *responseView; 103 | @property (unsafe_unretained) IBOutlet NSTextView *requestHeadersSentText; 104 | @property (weak) IBOutlet NSTextField *status; 105 | @property (weak) IBOutlet NSProgressIndicator *progressIndicator; 106 | @property (unsafe_unretained) IBOutlet NSTextView *responseTextPlain; 107 | @property (weak) IBOutlet NSScrollView *responseTextPlainView; 108 | 109 | // Saved Requests 110 | @property (weak) IBOutlet CRCDrawerView *savedRequestsView; 111 | @property (weak) IBOutlet NSOutlineView *savedOutlineView; 112 | @property (weak) IBOutlet NSSplitView *verticalSplitView; 113 | @property (weak) IBOutlet NSVisualEffectView *savedRequestsOuterView; 114 | @property (weak) IBOutlet NSVisualEffectView *savedRequestsInnerView; 115 | @property CGFloat lastSavedRequestsViewWidth; 116 | 117 | // For modal dialogs 118 | @property (weak) IBOutlet NSPanel *saveRequestSheet; 119 | @property (weak) IBOutlet NSPanel *timeoutSheet; 120 | @property (weak) IBOutlet NSTextField *timeoutField; 121 | 122 | - (void) initHighlightedViews; 123 | - (NSTouchBarItem *) touchBarButtonWithTitle:(NSString *)title color:(NSColor *)color identifier:(NSTouchBarItemIdentifier)identifier 124 | target:(id)target selector:(SEL)selector; 125 | 126 | // Request Manipulation 127 | - (void) setRequestText:(NSString *)request; 128 | - (NSString *) getRequestText; 129 | - (IBAction) doubleClickedHeaderRow:(id)sender; 130 | - (IBAction) plusHeaderRow:(id)sender; 131 | - (IBAction) minusHeaderRow:(id)sender; 132 | - (void) doneEditingHeaderRow:(TableRowAndColumn *)tableRowAndColumn; 133 | - (IBAction) clearAuth:(id)sender; 134 | - (IBAction) doubleClickedFileRow:(id)sender; 135 | - (IBAction) plusFileRow:(id)sender; 136 | - (IBAction) minusFileRow:(id)sender; 137 | - (void) addFileToFilesTable: (NSURL*) fileUrl; 138 | - (IBAction) doubleClickedParamsRow:(id)sender; 139 | - (IBAction) plusParamsRow:(id)sender; 140 | - (IBAction) minusParamsRow:(id)sender; 141 | - (void) doneEditingParamsRow:(TableRowAndColumn *)tableRowAndColumn; 142 | - (void) selectRequestBodyInputMode; 143 | - (IBAction)requestBodyInputMode:(id)sender; 144 | - (void) contentTypeMenuItemSelected:(id)sender; 145 | - (void)deleteTableRow:(NSNotification *)notification; 146 | - (IBAction) plusUrlParamsRow:(id)sender; 147 | - (IBAction) minusUrlParamsRow:(id)sender; 148 | - (void) updateUrlFromParamsTable; 149 | - (BOOL) updateParamsTableFromUrl; 150 | - (void) urlBoxTextEdited:(NSNotification *)notification; 151 | - (IBAction) doubleClickedUrlRow:(id)sender; 152 | - (void) doneEditingUrlParamsRow:(TableRowAndColumn *)tableRowAndColumn; 153 | 154 | // Request submission and Response Handling 155 | - (IBAction) runSubmit:(id)sender; 156 | - (void) runGetSubmit; 157 | - (void) runPostSubmit; 158 | - (void) runPutSubmit; 159 | - (NSString *) getValueForHeader:(NSString *)headerName; 160 | - (void) setResponseText:(NSString *)response; 161 | - (NSString *) getResponseText; 162 | - (void) prettyPrintJsonResponseFromObject:(id)obj; 163 | - (void) prettyPrintJsonResponseFromString:(NSData*)jsonData; 164 | - (void) printResponsePlain; 165 | - (NSString *) substituteEnvVariables:(NSString *)stringTemplate; 166 | 167 | // Saved request handling 168 | - (void) loadSavedRequest:(id)request; 169 | - (IBAction) createNewSavedFolder:(id)sender; 170 | - (IBAction) deleteSavedRequestFromButton:(id) sender; 171 | - (void)loadSavedCRCRequest:(CRCRequest *)request; 172 | - (IBAction) outlineClick:(id)sender; 173 | - (void)loadSavedDictionary:(NSDictionary *)request __deprecated; 174 | - (void) adjustSavedRequestsViewWidth:(id)object; 175 | 176 | // Handling preference updates 177 | - (void)syntaxHighlightingPreferenceChanged; 178 | - (void) applyShowLineNumbers:(BOOL)show; 179 | - (void) darkModeChanged:(id) sender; 180 | 181 | @end 182 | -------------------------------------------------------------------------------- /core/PreferencesController.h: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 2/25/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PreferencesController : NSWindowController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /core/PreferencesController.m: -------------------------------------------------------------------------------- 1 | // 2 | // PreferencesController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 2/25/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "PreferencesController.h" 10 | 11 | @implementation PreferencesController 12 | 13 | - (id)initWithWindow:(NSWindow *)window { 14 | self = [super initWithWindow:window]; 15 | if (self) { 16 | // Initialization code here. 17 | } 18 | 19 | return self; 20 | } 21 | 22 | - (void)windowDidLoad { 23 | [super windowDidLoad]; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /core/SaveRequestPanelController.h: -------------------------------------------------------------------------------- 1 | // 2 | // SaveRequestPanelController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/21/17. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface SaveRequestPanelController : NSWindowController { 12 | NSTextField *saveRequestTextField; 13 | } 14 | 15 | @property (strong, nonnull) IBOutlet NSTextField *saveRequestTextField; 16 | @property (weak) IBOutlet NSWindow *parent; 17 | 18 | - (IBAction) save:(nullable id)sender; 19 | - (IBAction) cancel:(nullable id)sender; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /core/SaveRequestPanelController.m: -------------------------------------------------------------------------------- 1 | // 2 | // SaveRequestPanelController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/21/17. 6 | // 7 | // 8 | 9 | #import "SaveRequestPanelController.h" 10 | 11 | @implementation SaveRequestPanelController 12 | 13 | @synthesize saveRequestTextField; 14 | @synthesize parent; 15 | 16 | - (IBAction) save:(nullable id)sender { 17 | [parent endSheet:self.window returnCode:NSModalResponseOK]; 18 | } 19 | 20 | - (IBAction) cancel:(nullable id)sender { 21 | [parent endSheet:self.window returnCode:NSModalResponseCancel]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /core/SavedRequestsDataSource.h: -------------------------------------------------------------------------------- 1 | // 2 | // SavedRequestsDataSource.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/17/17. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @class CocoaRestClientAppDelegate; 12 | 13 | @interface SavedRequestsDataSource : NSObject { 14 | @private NSString *appDataFilePath; 15 | @private CocoaRestClientAppDelegate *appDelegate; 16 | } 17 | 18 | @property (class, atomic, strong) NSMutableArray *savedRequestsArray; 19 | 20 | - (void) saveDataToDisk; 21 | - (void) loadDataFromDisk; 22 | - (NSString *) pathForDataFile; 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /core/SavedRequestsDataSource.m: -------------------------------------------------------------------------------- 1 | // 2 | // SavedRequestsDataSource.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/17/17. 6 | // 7 | // 8 | 9 | #import "SavedRequestsDataSource.h" 10 | #import "CRCSavedRequestFolder.h" 11 | #import "CRCRequest.h" 12 | #import "CRCConstants.h" 13 | #import "CocoaRestClientAppDelegate.h" 14 | 15 | @implementation SavedRequestsDataSource 16 | 17 | static NSMutableArray* _savedRequestsArray = nil; 18 | 19 | + (NSMutableArray *) savedRequestsArray { 20 | return _savedRequestsArray; 21 | } 22 | 23 | + (void) setSavedRequestsArray:(NSMutableArray *)array { 24 | _savedRequestsArray = array; 25 | } 26 | 27 | - (id) init { 28 | self = [super init]; 29 | 30 | appDelegate = (CocoaRestClientAppDelegate *)[NSApp delegate]; 31 | 32 | return self; 33 | } 34 | 35 | - (NSInteger) outlineView: (NSOutlineView *)outlineView numberOfChildrenOfItem: (id)item { 36 | if (item == nil) { 37 | return [SavedRequestsDataSource.savedRequestsArray count]; 38 | } else { 39 | return [item count]; 40 | } 41 | } 42 | 43 | - (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item { 44 | if (item == nil) return NO; 45 | return [item isKindOfClass:[CRCSavedRequestFolder class]]; 46 | } 47 | 48 | - (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item { 49 | if (item == nil) { 50 | return [SavedRequestsDataSource.savedRequestsArray objectAtIndex:index]; 51 | } else { 52 | return [item objectAtIndex:index]; 53 | } 54 | } 55 | 56 | - (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { 57 | if ([item isKindOfClass:[CRCRequest class]]) 58 | { 59 | CRCRequest * req = (CRCRequest *)item; 60 | return req.name; 61 | } 62 | else if ([item isKindOfClass:[CRCSavedRequestFolder class]]) 63 | { 64 | return ((CRCSavedRequestFolder *)item).name; 65 | } 66 | else if (item == SavedRequestsDataSource.savedRequestsArray) { 67 | return SavedRequestsDataSource.savedRequestsArray; 68 | } 69 | 70 | return nil; 71 | } 72 | 73 | - (void) outlineView:(NSOutlineView *)outlineView setObjectValue:(id)object forTableColumn:(NSTableColumn *)tableColumn byItem:(id)item { 74 | if ([item isKindOfClass:[CRCRequest class]]) { 75 | CRCRequest * req = (CRCRequest *)item; 76 | req.name = object; 77 | } 78 | else if ([item isKindOfClass:[CRCSavedRequestFolder class]]) { 79 | ((CRCSavedRequestFolder *)item).name = object; 80 | } 81 | } 82 | 83 | #pragma mark OutlineView drag and drop methods 84 | - (id )outlineView:(NSOutlineView *)outlineView pasteboardWriterForItem:(id)item{ 85 | // No dragging if 86 | BOOL dragAllowed = YES; 87 | if (!dragAllowed) { 88 | return nil; 89 | } 90 | 91 | NSPasteboardItem *pboardItem = [[NSPasteboardItem alloc] init]; 92 | NSString *idStr = [NSString stringWithFormat:@"%ld", (long) item]; 93 | [pboardItem setString:idStr forType: @"public.text"]; 94 | NSLog(@"%@", idStr); 95 | 96 | return pboardItem; 97 | } 98 | 99 | 100 | - (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id < NSDraggingInfo >)info proposedItem:(id)targetItem proposedChildIndex:(NSInteger)index{ 101 | 102 | if (index >= 0) { 103 | return NSDragOperationMove; 104 | } else { 105 | return NSDragOperationNone; 106 | } 107 | } 108 | 109 | 110 | - (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id < NSDraggingInfo >)info item:(id)targetItem childIndex:(NSInteger)targetIndex{ 111 | 112 | NSPasteboard *p = [info draggingPasteboard]; 113 | NSString *objId = [p stringForType:@"public.text"]; 114 | NSLog(@"Pasteboad item = %@", objId); 115 | 116 | id sourceItem = nil; 117 | CRCSavedRequestFolder *sourceParentFolder = nil; 118 | int sourceIndex = -1; 119 | 120 | for (id entry in SavedRequestsDataSource.savedRequestsArray) { 121 | if ([[NSString stringWithFormat:@"%ld", (long) entry] isEqualToString:objId]) { 122 | sourceItem = entry; 123 | sourceIndex = [SavedRequestsDataSource.savedRequestsArray indexOfObject:sourceItem]; 124 | } else if ([entry isKindOfClass:[CRCSavedRequestFolder class]]) { 125 | id recursiveParent = [((CRCSavedRequestFolder *)entry) findParentOfObjectWith:objId]; 126 | if (recursiveParent) { 127 | sourceParentFolder = recursiveParent; 128 | sourceItem = [((CRCSavedRequestFolder *)sourceParentFolder) findObjectWith:objId]; 129 | sourceIndex = [((CRCSavedRequestFolder *)sourceParentFolder) findIndexOfObject:sourceItem]; 130 | } 131 | } 132 | } 133 | 134 | // Unclear how this would happen, but we don't know what we are moving 135 | if (! sourceItem) { 136 | NSLog(@"Unable to find source item dropped into list"); 137 | return NO; 138 | } 139 | 140 | if (sourceIndex == -1) { 141 | NSLog(@"Unable to find index of moving item"); 142 | return NO; 143 | } 144 | 145 | if (targetItem == sourceItem) { 146 | return NO; 147 | } 148 | 149 | if (sourceParentFolder) { 150 | [((CRCSavedRequestFolder *) sourceParentFolder) removeObject:sourceItem]; 151 | } else { 152 | [SavedRequestsDataSource.savedRequestsArray removeObject:sourceItem]; 153 | } 154 | 155 | NSLog(@"Found source item of drop: %@ with parent %@", sourceItem, sourceParentFolder); 156 | 157 | if (! targetItem) { 158 | // Saving into the top level array 159 | if (sourceParentFolder == nil && (targetIndex > sourceIndex)) { 160 | targetIndex--; 161 | } 162 | [SavedRequestsDataSource.savedRequestsArray insertObject:sourceItem atIndex:targetIndex]; 163 | [appDelegate redrawRequestViews]; 164 | [self saveDataToDisk]; 165 | return YES; 166 | } else { 167 | // Saving into a sub-folder 168 | NSLog(@"TargetIndex = %ld and sourceIndex = %d", targetIndex, sourceIndex); 169 | if (sourceParentFolder == targetItem && (targetIndex > sourceIndex)) { 170 | targetIndex--; 171 | } 172 | [((CRCSavedRequestFolder *) targetItem) insertObject:sourceItem atIndex:targetIndex]; 173 | [appDelegate redrawRequestViews]; 174 | [self saveDataToDisk]; 175 | return YES; 176 | } 177 | 178 | } 179 | 180 | - (void) saveDataToDisk { 181 | NSString *path = [self pathForDataFile]; 182 | [NSKeyedArchiver archiveRootObject:SavedRequestsDataSource.savedRequestsArray toFile:path]; 183 | } 184 | 185 | - (void) loadDataFromDisk { 186 | NSString *path = [self pathForDataFile]; 187 | SavedRequestsDataSource.savedRequestsArray = [[NSMutableArray alloc] initWithArray:[NSKeyedUnarchiver unarchiveObjectWithFile:path]]; 188 | } 189 | 190 | - (NSString *) pathForDataFile { 191 | if (!appDataFilePath) { 192 | NSArray *allPaths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES); 193 | NSString *dir = [[allPaths objectAtIndex: 0] stringByAppendingPathComponent: APPLICATION_NAME]; 194 | if (!dir) { 195 | NSLog(@"Can not locate the Application Support directory. Weird."); 196 | return nil; 197 | } 198 | NSFileManager *fileManager = [NSFileManager defaultManager]; 199 | NSError *error = nil; 200 | BOOL success = [fileManager createDirectoryAtPath: dir withIntermediateDirectories: YES 201 | attributes: nil error: &error]; 202 | if (!success) { 203 | NSLog(@"Can not create a support directory.\n%@", [error localizedDescription]); 204 | return nil; 205 | } 206 | appDataFilePath = [dir stringByAppendingPathComponent: DATAFILE_NAME]; 207 | 208 | // On first time startup of version 1.3.8 of the app, backup the data file since the format 209 | // will make it backwards incompatible. 210 | NSString *backupDataFilePath = [dir stringByAppendingPathComponent:BACKUP_DATAFILE_1_3_8]; 211 | if (! [fileManager fileExistsAtPath:backupDataFilePath]) { 212 | NSError *error = nil; 213 | [fileManager copyItemAtPath:appDataFilePath toPath:backupDataFilePath error:&error]; 214 | if (! error) { 215 | NSLog(@"Successfully backed up 1.3.8 datafile as: %@", backupDataFilePath); 216 | } else { 217 | NSLog(@"Error backing up old data file: %@", [error localizedDescription]); 218 | } 219 | } 220 | } 221 | return appDataFilePath; 222 | } 223 | 224 | 225 | @end 226 | -------------------------------------------------------------------------------- /core/SelectableSavedRequestWrapper.h: -------------------------------------------------------------------------------- 1 | // 2 | // SelectableSavedRequestWrapper.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/11/17. 6 | // 7 | // 8 | 9 | #import 10 | #import "CRCRequest.h" 11 | 12 | @interface SelectableSavedRequestWrapper : NSObject 13 | 14 | @property (nonatomic, retain) CRCRequest* request; 15 | @property (nonatomic, retain) NSString* path; 16 | 17 | + (SelectableSavedRequestWrapper *) initWithRequest:(CRCRequest *)request withPath:(NSString*)path; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /core/SelectableSavedRequestWrapper.m: -------------------------------------------------------------------------------- 1 | // 2 | // SelectableSavedRequestWrapper.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/11/17. 6 | // 7 | // 8 | 9 | #import "SelectableSavedRequestWrapper.h" 10 | 11 | @implementation SelectableSavedRequestWrapper 12 | 13 | @synthesize request; 14 | @synthesize path; 15 | 16 | + (SelectableSavedRequestWrapper *) initWithRequest:(CRCRequest *)request withPath:(NSString*)path { 17 | SelectableSavedRequestWrapper *reqWrapper = [[SelectableSavedRequestWrapper alloc] init]; 18 | reqWrapper.request = request; 19 | reqWrapper.path = path; 20 | return reqWrapper; 21 | } 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /core/TimeoutPanelController.h: -------------------------------------------------------------------------------- 1 | // 2 | // TimeoutPanelController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/24/17. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface TimeoutPanelController : NSWindowController { 12 | NSTextField *timeoutTextField; 13 | } 14 | 15 | @property (strong, nonnull) IBOutlet NSTextField *timeoutTextField; 16 | @property (weak) IBOutlet NSWindow *parent; 17 | 18 | - (IBAction) ok:(nullable id)sender; 19 | - (IBAction) cancel:(nullable id)sender; 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /core/TimeoutPanelController.m: -------------------------------------------------------------------------------- 1 | // 2 | // TimeoutPanelController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 5/24/17. 6 | // 7 | // 8 | 9 | #import "TimeoutPanelController.h" 10 | 11 | @implementation TimeoutPanelController 12 | 13 | @synthesize timeoutTextField; 14 | @synthesize parent; 15 | 16 | - (void)windowDidLoad { 17 | [super windowDidLoad]; 18 | 19 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 20 | } 21 | 22 | - (IBAction) ok:(nullable id)sender { 23 | [parent endSheet:self.window returnCode:NSModalResponseOK]; 24 | } 25 | 26 | - (IBAction) cancel:(nullable id)sender { 27 | [parent endSheet:self.window returnCode:NSModalResponseCancel]; 28 | } 29 | 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /core/WelcomeController.h: -------------------------------------------------------------------------------- 1 | // 2 | // WelcomeController.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 8/5/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface WelcomeController : NSWindowController { 12 | NSTextView *messageText; 13 | } 14 | 15 | @property (strong) IBOutlet NSTextView *messageText; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /core/WelcomeController.m: -------------------------------------------------------------------------------- 1 | // 2 | // WelcomeController.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 8/5/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "WelcomeController.h" 10 | 11 | @implementation WelcomeController 12 | 13 | @synthesize messageText; 14 | 15 | - (id)initWithWindow:(NSWindow *)window 16 | { 17 | self = [super initWithWindow:window]; 18 | if (self) { 19 | // Initialization code here. 20 | } 21 | 22 | return self; 23 | } 24 | 25 | - (void)windowDidLoad 26 | { 27 | [super windowDidLoad]; 28 | 29 | // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. 30 | if ([messageText string] == nil || [[messageText string] isEqualToString:@""]) { 31 | [messageText setString:[NSString stringWithContentsOfFile: 32 | [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"motd.txt"] encoding:NSUTF8StringEncoding error:nil]]; 33 | [messageText setFont:[NSFont fontWithName:@"Verdana" size:14.0]]; 34 | } 35 | } 36 | 37 | @end 38 | -------------------------------------------------------------------------------- /core/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // CocoaRestClient 4 | // 5 | // Created by mmattozzi on 1/5/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **) argv); 14 | } 15 | -------------------------------------------------------------------------------- /defaults.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIDisableAnimations 6 | 7 | UIMenuSyntaxHighlight 8 | 9 | UIRawRequestBody 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /request/CRCFileRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCFileRequest.h 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CocoaRestClientAppDelegate.h" 11 | 12 | @class MainWindowController; 13 | 14 | @interface CRCFileRequest : NSObject { 15 | 16 | } 17 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController; 18 | + (BOOL) currentRequestIsCRCFileRequest:(MainWindowController *)windowController; 19 | @end 20 | -------------------------------------------------------------------------------- /request/CRCFileRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCFileRequest.m 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CRCFileRequest.h" 10 | #import "CocoaRestClientAppDelegate.h" 11 | #import "MainWindowController.h" 12 | 13 | @implementation CRCFileRequest 14 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController 15 | { 16 | NSMutableData * body = [NSMutableData data]; 17 | 18 | NSURL * path = [[windowController.filesTable objectAtIndex:0] objectForKey:@"url"]; 19 | 20 | if([[NSFileManager defaultManager] fileExistsAtPath:[path relativePath]]) 21 | { 22 | 23 | [body appendData:[NSData dataWithContentsOfFile:[path relativePath]]]; 24 | [request setHTTPBody: body]; 25 | } 26 | } 27 | 28 | +(BOOL) currentRequestIsCRCFileRequest:(MainWindowController *)windowController { 29 | return [windowController.filesTable count] > 0 && [[windowController getRequestText] isEqualToString:@""] && 30 | [[NSUserDefaults standardUserDefaults]boolForKey:RAW_REQUEST_BODY]; 31 | } 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /request/CRCFormEncodedRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCFormEncodedRequest.h 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MainWindowController; 12 | 13 | @interface CRCFormEncodedRequest : NSObject { 14 | 15 | } 16 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController; 17 | +(NSData *) createRequestBody:(NSArray *)params; 18 | @end 19 | -------------------------------------------------------------------------------- /request/CRCFormEncodedRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCFormEncodedRequest.m 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CRCFormEncodedRequest.h" 10 | #import "MainWindowController.h" 11 | 12 | @implementation CRCFormEncodedRequest 13 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController 14 | { 15 | NSData *body = nil; 16 | NSString * headerfield = @"application/x-www-form-urlencoded"; 17 | 18 | [request addValue:headerfield forHTTPHeaderField:@"Content-Type"]; 19 | 20 | if([windowController.paramsTable count] > 0) { 21 | body = [self createRequestBody:windowController.paramsTable]; 22 | [request setHTTPBody:body]; 23 | } 24 | 25 | } 26 | 27 | +(NSData *) createRequestBody:(NSArray *)params { 28 | NSMutableData * body = [NSMutableData data]; 29 | 30 | for(NSDictionary * row in params) 31 | { 32 | NSString * key = [row objectForKey:@"key"]; 33 | NSString * value = [row objectForKey:@"value"]; 34 | 35 | if([body length] > 0) { 36 | [body appendData:[@"&" dataUsingEncoding:NSUTF8StringEncoding]]; 37 | } 38 | 39 | // URL form encode the key for the parameter 40 | key = [key stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 41 | // For some reason, & and + are not escaped by stringByAddingPercentEscapesUsingEncoding 42 | key = [key stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; 43 | key = [key stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"]; 44 | 45 | // URL form encode the value of the parameter 46 | value = [value stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 47 | // For some reason, & and + are not escaped by stringByAddingPercentEscapesUsingEncoding 48 | value = [value stringByReplacingOccurrencesOfString:@"&" withString:@"%26"]; 49 | value = [value stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"]; 50 | 51 | [body appendData:[[NSString stringWithFormat:@"%@=%@", key, value] 52 | dataUsingEncoding:NSUTF8StringEncoding]]; 53 | } 54 | 55 | return body; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /request/CRCMultipartRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCMultipartRequest.h 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/8/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MainWindowController; 12 | 13 | @interface CRCMultipartRequest : NSObject { 14 | 15 | } 16 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController; 17 | +(NSString *)generateBoundary; 18 | @end 19 | -------------------------------------------------------------------------------- /request/CRCMultipartRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCMultipartRequest.m 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/8/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CRCMultipartRequest.h" 10 | #import "CocoaRestClientAppDelegate.h" 11 | #import "NSData+gzip.h" 12 | #import "MainWindowController.h" 13 | 14 | @implementation CRCMultipartRequest 15 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController 16 | { 17 | NSMutableData * body = [NSMutableData data]; 18 | NSString * formBoundary = [CRCMultipartRequest generateBoundary]; 19 | NSString * headerfield = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", formBoundary]; 20 | 21 | [request addValue:headerfield forHTTPHeaderField:@"Content-Type"]; 22 | 23 | if([windowController.paramsTable count] > 0) 24 | { 25 | for(NSDictionary * row in windowController.paramsTable) 26 | { 27 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n",formBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 28 | [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n%@", [row objectForKey:@"key"], [row objectForKey:@"value"]] dataUsingEncoding:NSUTF8StringEncoding]]; 29 | } 30 | } 31 | 32 | NSInteger count = [windowController.filesTable count]; 33 | if(count > 0) 34 | { 35 | for(NSDictionary * row in windowController.filesTable) 36 | { 37 | NSError *err = nil; 38 | NSString *uti; 39 | NSString *mimeType; 40 | 41 | NSURL *path = [row objectForKey:@"url"]; 42 | 43 | if([[NSFileManager defaultManager] fileExistsAtPath:[path relativePath]]) 44 | { 45 | 46 | if (!(uti = [[NSWorkspace sharedWorkspace] typeOfFile:[path relativePath] error:&err])) 47 | { 48 | mimeType = @"application/octet-stream"; 49 | } 50 | else if ((mimeType = (__bridge NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)uti, kUTTagClassMIMEType))) 51 | { 52 | // TODO ??? 53 | } 54 | 55 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", formBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 56 | [body appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [row objectForKey:@"key"],[[path relativePath] lastPathComponent]] dataUsingEncoding:NSUTF8StringEncoding]]; 57 | 58 | if ([[row objectForKey: @"gzip"] boolValue]) 59 | { 60 | [body appendData: [@"Content-Type: application/x-gzip\r\n\r\n" dataUsingEncoding: NSUTF8StringEncoding]]; 61 | [body appendData: [[NSData dataWithContentsOfFile: [path relativePath]] gzipped]]; 62 | } 63 | else 64 | { 65 | /* A «smarter» way, perhaps */ 66 | if ( ! [[NSWorkspace sharedWorkspace] type: uti conformsToType: (NSString *)kUTTypeText]) 67 | { 68 | [body appendData: [@"Content-Transfer-Encoding: binary\r\n" dataUsingEncoding:NSUTF8StringEncoding]]; 69 | } 70 | [body appendData: [[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", mimeType] dataUsingEncoding:NSUTF8StringEncoding]]; 71 | [body appendData: [NSData dataWithContentsOfFile: [path relativePath]]]; 72 | } 73 | } 74 | } 75 | 76 | } 77 | 78 | [body appendData:[[NSString stringWithFormat:@"\r\n--%@--\r\n", formBoundary] dataUsingEncoding:NSUTF8StringEncoding]]; 79 | [request setHTTPBody: body]; 80 | } 81 | 82 | +(NSString *)generateBoundary 83 | { 84 | CFUUIDRef uuidRef = CFUUIDCreate(kCFAllocatorDefault); 85 | CFStringRef stringRef = CFUUIDCreateString(kCFAllocatorDefault, uuidRef); 86 | NSString *uuid = [NSString stringWithString:(NSString*)CFBridgingRelease(stringRef)]; 87 | 88 | CFRelease(uuidRef); 89 | 90 | return uuid; 91 | } 92 | @end 93 | -------------------------------------------------------------------------------- /request/CRCRawRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCRawRequest.h 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MainWindowController; 12 | 13 | @interface CRCRawRequest : NSObject { 14 | 15 | } 16 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController; 17 | @end 18 | -------------------------------------------------------------------------------- /request/CRCRawRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCRawRequest.m 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CRCRawRequest.h" 10 | #import "CocoaRestClientAppDelegate.h" 11 | #import "MainWindowController.h" 12 | 13 | @implementation CRCRawRequest 14 | +(void)createRequest:(NSMutableURLRequest *)request withWindow:(MainWindowController *)windowController 15 | { 16 | NSMutableData * body = [NSMutableData data]; 17 | [body appendData:[[windowController getRequestText] dataUsingEncoding:NSUTF8StringEncoding]]; 18 | [request setHTTPBody: body]; 19 | } 20 | @end 21 | -------------------------------------------------------------------------------- /request/CRCRequest.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCSaveRequest.h 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CRCConstants.h" 11 | 12 | @class MainWindowController; 13 | 14 | enum { 15 | CRCContentTypeMultipart, 16 | CRCContentTypeFormEncoded, 17 | CRCContentTypeJson, 18 | CRCContentTypeXml, 19 | CRCContentTypeImage, 20 | CRCContentTypeUnknown 21 | }; 22 | typedef NSInteger CRCContentType; 23 | 24 | @interface CRCRequest : NSObject { 25 | BOOL rawRequestInput; 26 | NSString * name; 27 | NSString * url; 28 | NSString * method; 29 | NSString * requestText; 30 | NSString * username; 31 | NSString * password; 32 | NSArray * headers; 33 | NSArray * files; 34 | NSArray * params; 35 | BOOL preemptiveBasicAuth; 36 | } 37 | 38 | @property BOOL rawRequestInput; 39 | @property(nonatomic, copy) NSString * name; 40 | @property(nonatomic, copy) NSString * url; 41 | @property(nonatomic, copy) NSString * method; 42 | @property(nonatomic, copy) NSString * requestText; 43 | @property(nonatomic, copy) NSString * username; 44 | @property(nonatomic, copy) NSString * password; 45 | @property(nonatomic, copy) NSArray * headers; 46 | @property(nonatomic, copy) NSArray * files; 47 | @property(nonatomic, copy) NSArray * params; 48 | @property BOOL preemptiveBasicAuth; 49 | 50 | + (CRCRequest *)requestWithWindow:(MainWindowController *)mainWindowController named:(NSString *)name; 51 | - (CRCRequest *)overwriteContentsWith:(CRCRequest *)request; 52 | - (NSString *) generateCurlCommand:(bool)followRedirects; 53 | + (CRCContentType) determineRequestContentType:(NSArray *)headers; 54 | 55 | @end 56 | -------------------------------------------------------------------------------- /request/CRCRequest.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCSaveRequest.m 3 | // CocoaRestClient 4 | // 5 | // Created by Adam Venturella on 7/10/10. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CRCRequest.h" 10 | #import "CRCFormEncodedRequest.h" 11 | #import "MainWindowController.h" 12 | 13 | 14 | @implementation CRCRequest 15 | @synthesize name, url, method, rawRequestInput, requestText, username, password, headers, files, params, preemptiveBasicAuth; 16 | 17 | + (CRCRequest *)requestWithWindow:(MainWindowController *)mainWindowController named:(NSString *)name 18 | { 19 | 20 | CRCRequest * request = [[CRCRequest alloc] init]; 21 | 22 | request.name = name; 23 | request.url = [mainWindowController.urlBox stringValue]; 24 | request.method = [mainWindowController.methodButton stringValue]; 25 | request.username = [mainWindowController.username stringValue]; 26 | request.password = [mainWindowController.password stringValue]; 27 | request.rawRequestInput = mainWindowController.rawRequestBody; 28 | request.preemptiveBasicAuth = mainWindowController.preemptiveBasicAuth; 29 | 30 | if(request.rawRequestInput) 31 | request.requestText = [mainWindowController getRequestText]; 32 | 33 | if([mainWindowController.headersTable count] > 0) 34 | request.headers = [[NSArray alloc] initWithArray:mainWindowController.headersTable copyItems:YES]; 35 | 36 | if([mainWindowController.paramsTable count] > 0 && !request.rawRequestInput) 37 | request.params = [[NSArray alloc] initWithArray:mainWindowController.paramsTable copyItems:YES]; 38 | 39 | if([mainWindowController.filesTable count] > 0) 40 | request.files = [[NSArray alloc] initWithArray:mainWindowController.filesTable copyItems:YES]; 41 | 42 | return request; 43 | } 44 | 45 | /** Overwrite all fields except the name with the contents of the input request. */ 46 | - (CRCRequest *)overwriteContentsWith:(CRCRequest *)request { 47 | self.url = request.url; 48 | self.method = request.method; 49 | self.username = request.username; 50 | self.password = request.password; 51 | self.rawRequestInput = request.rawRequestInput; 52 | self.preemptiveBasicAuth = request.preemptiveBasicAuth; 53 | self.requestText = request.requestText; 54 | self.headers = request.headers; 55 | self.params = request.params; 56 | self.files = request.files; 57 | return self; 58 | } 59 | 60 | - (void) encodeWithCoder: (NSCoder *)coder 61 | { 62 | [coder encodeBool: self.rawRequestInput forKey: @"rawRequestInput"]; 63 | [coder encodeObject: self.name forKey: @"name"]; 64 | [coder encodeObject: self.url forKey: @"url"]; 65 | [coder encodeObject: self.method forKey: @"method"]; 66 | [coder encodeObject: self.requestText forKey: @"requestText"]; 67 | [coder encodeObject: self.username forKey: @"username"]; 68 | [coder encodeObject: self.password forKey: @"password"]; 69 | [coder encodeObject: self.headers forKey: @"headers"]; 70 | [coder encodeObject: self.files forKey: @"files"]; 71 | [coder encodeObject: self.params forKey: @"params"]; 72 | [coder encodeBool: self.preemptiveBasicAuth forKey:@"preemptiveBasicAuth"]; 73 | } 74 | 75 | - (id) initWithCoder: (NSCoder *)coder 76 | { 77 | if (self = [super init]) 78 | { 79 | rawRequestInput = [coder decodeBoolForKey: @"rawRequestInput"]; 80 | name = [coder decodeObjectForKey: @"name"]; 81 | url = [coder decodeObjectForKey: @"url"]; 82 | method = [coder decodeObjectForKey: @"method"]; 83 | requestText = [coder decodeObjectForKey: @"requestText"]; 84 | username = [coder decodeObjectForKey: @"username"]; 85 | password = [coder decodeObjectForKey: @"password"]; 86 | headers = [coder decodeObjectForKey: @"headers"]; 87 | files = [coder decodeObjectForKey: @"files"]; 88 | params = [coder decodeObjectForKey: @"params"]; 89 | if ([coder containsValueForKey:@"preemptiveBasicAuth"]) { 90 | preemptiveBasicAuth = [coder decodeBoolForKey:@"preemptiveBasicAuth"]; 91 | } else { 92 | preemptiveBasicAuth = NO; 93 | } 94 | } 95 | 96 | return self; 97 | } 98 | 99 | + (CRCContentType) determineRequestContentType:(NSArray *) headers { 100 | CRCContentType requestContentType = CRCContentTypeUnknown; 101 | 102 | for(NSDictionary * row in headers) 103 | { 104 | if([[[row objectForKey:@"key"] lowercaseString] isEqualToString:@"content-type"]) 105 | { 106 | NSString * value = [[row objectForKey:@"value"] lowercaseString]; 107 | NSRange range; 108 | 109 | if([value isEqualToString:@"application/x-www-form-urlencoded"]){ 110 | requestContentType = CRCContentTypeFormEncoded; 111 | break; 112 | } 113 | 114 | if([value isEqualToString:@"multipart/form-data"]){ 115 | requestContentType = CRCContentTypeMultipart; 116 | break; 117 | } 118 | 119 | range = [value rangeOfString:@"json"]; 120 | if(range.length > 0){ 121 | requestContentType = CRCContentTypeJson; 122 | break; 123 | } 124 | 125 | range = [value rangeOfString:@"xml"]; 126 | if(range.length > 0){ 127 | requestContentType = CRCContentTypeXml; 128 | break; 129 | } 130 | 131 | range = [value rangeOfString:@"image"]; 132 | if(range.length > 0){ 133 | requestContentType = CRCContentTypeImage; 134 | break; 135 | } 136 | } 137 | } 138 | 139 | return requestContentType; 140 | } 141 | 142 | - (NSString *) generateCurlCommand:(bool)followRedirects { 143 | NSMutableString *command = [NSMutableString stringWithCapacity:500]; 144 | [command appendString:@"curl -k "]; 145 | if (followRedirects) { 146 | [command appendString:@" -L "]; 147 | } 148 | if (! [method isEqualToString:@"GET"]) { 149 | [command appendString:[NSString stringWithFormat:@"-X %@ ", method]]; 150 | } 151 | 152 | for (NSDictionary *header in headers) { 153 | if ([[[header valueForKey:@"key"] lowercaseString] isEqualToString:@"accept-encoding"]) { 154 | [command appendString:@"--compressed "]; 155 | } 156 | } 157 | 158 | for (NSDictionary *header in headers) { 159 | [command appendString:[NSString stringWithFormat:@"-H '%@: %@' ", [header valueForKey:@"key"], [header valueForKey:@"value"]]]; 160 | } 161 | 162 | CRCContentType contentType = [CRCRequest determineRequestContentType:headers]; 163 | 164 | if (contentType != CRCContentTypeFormEncoded) { 165 | for (NSDictionary *param in params) { 166 | [command appendString:[NSString stringWithFormat:@"-F '%@=%@' ", [param valueForKey:@"key"], [param valueForKey:@"value"]]]; 167 | } 168 | } else if (! rawRequestInput && [params count] > 0) { 169 | [command appendString:[NSString stringWithFormat:@"-d '%@' ", 170 | [[NSString alloc] initWithData:[CRCFormEncodedRequest createRequestBody:params] encoding:NSUTF8StringEncoding]]]; 171 | } 172 | 173 | if (rawRequestInput && [requestText length] > 0) { 174 | [command appendString:[NSString stringWithFormat:@"-d '%@' ", requestText]]; 175 | } 176 | 177 | if (username && password && ([username length] > 0 || [password length] > 0)) { 178 | [command appendString:[NSString stringWithFormat:@"-u '%@:%@' ", username, password]]; 179 | } 180 | 181 | if (contentType == CRCContentTypeMultipart) { 182 | for (NSDictionary *fileParam in files) { 183 | NSString *filePath = [[fileParam valueForKey:@"url"] absoluteString]; 184 | if ([filePath hasPrefix:@"file://"]) { 185 | filePath = [filePath substringFromIndex:7]; 186 | } 187 | [command appendString:[NSString stringWithFormat:@"-F '%@=@%@' ", [fileParam valueForKey:@"key"], filePath]]; 188 | } 189 | } 190 | 191 | [command appendString:[NSString stringWithFormat:@"'%@'", url]]; 192 | 193 | return command; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /request/CRCSavedRequestFolder.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCSavedRequestFolder.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 3/15/14. 6 | // Copyright (c) 2014 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface CRCSavedRequestFolder : NSObject { 12 | NSString *name; 13 | NSMutableArray *contents; 14 | } 15 | 16 | @property(nonatomic, copy) NSString *name; 17 | @property(nonatomic, copy) NSMutableArray *contents; 18 | 19 | - (id) init; 20 | - (NSUInteger)count; 21 | - (void) addObject:(id) object; 22 | - (void) insertObject:(id) object atIndex:(NSUInteger)index; 23 | - (id) objectAtIndex:(NSUInteger)index; 24 | - (void) removeObject:(id) object; 25 | - (id) findObjectWith:(NSString *) objId; 26 | - (id) findParentOfObjectWith:(NSString *) objId; 27 | - (int) findIndexOfObject:(id) obj; 28 | 29 | - (void)encodeWithCoder:(NSCoder *)coder; 30 | - (id)initWithCoder:(NSCoder *)coder; 31 | 32 | @end -------------------------------------------------------------------------------- /request/CRCSavedRequestFolder.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCSavedRequestFolder.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 3/15/14. 6 | // Copyright (c) 2014 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "CRCSavedRequestFolder.h" 10 | 11 | @implementation CRCSavedRequestFolder 12 | @synthesize name; 13 | @synthesize contents; 14 | 15 | - (NSUInteger)count { 16 | return [contents count]; 17 | } 18 | 19 | - (void) addObject:(id) object { 20 | [contents addObject:object]; 21 | } 22 | 23 | - (void) insertObject:(id) object atIndex:(NSUInteger)index { 24 | [contents insertObject:object atIndex:index]; 25 | } 26 | 27 | - (id) objectAtIndex:(NSUInteger)index { 28 | return [contents objectAtIndex:index]; 29 | } 30 | 31 | // Recursively remove object from any embedded CRCSavedRequestFolders 32 | - (void) removeObject:(id) object { 33 | if ([contents containsObject:object]) { 34 | [contents removeObject:object]; 35 | } else { 36 | for (id entry in contents) { 37 | if ([entry isKindOfClass:[CRCSavedRequestFolder class]]) { 38 | [((CRCSavedRequestFolder *)entry) removeObject:object]; 39 | } 40 | } 41 | } 42 | } 43 | 44 | - (void)setContents:(NSMutableArray *)array { 45 | contents = [array mutableCopy]; 46 | } 47 | 48 | /** 49 | * Recursively search all subfolders and return the object matching the id requested. 50 | * Returns self if self matches the given id. 51 | */ 52 | - (id) findObjectWith:(NSString *) objId { 53 | id object = nil; 54 | if ([[NSString stringWithFormat:@"%ld", (long) self] isEqualToString:objId]) { 55 | object = self; 56 | } else { 57 | for (id entry in contents) { 58 | if (! [entry isKindOfClass:[CRCSavedRequestFolder class]]) { 59 | if ([[NSString stringWithFormat:@"%ld", (long) entry] isEqualToString:objId]) { 60 | object = entry; 61 | } 62 | } else { 63 | id recursiveObj = [((CRCSavedRequestFolder *)entry) findObjectWith:objId]; 64 | if (recursiveObj) { 65 | object = recursiveObj; 66 | } 67 | } 68 | } 69 | } 70 | 71 | return object; 72 | } 73 | 74 | /** 75 | * Recursively search contents and subfolders and return the index of the object specified, in 76 | * whatever subfolder it was located. For example, if we are searching for object x in: 77 | * - a 78 | * + b 79 | * + c 80 | * - d 81 | * - e 82 | * - x 83 | * The returned integer would be 2. If the object is not found, return -1. 84 | */ 85 | - (int) findIndexOfObject:(id) obj { 86 | int index = -1; 87 | for (int i = 0; i < [contents count]; i++) { 88 | id entry = [contents objectAtIndex:i]; 89 | if (entry == obj) { 90 | index = i; 91 | } else if ([entry isKindOfClass:[CRCSavedRequestFolder class]]) { 92 | int recursiveIndex = [((CRCSavedRequestFolder *)entry) findIndexOfObject:obj]; 93 | if (recursiveIndex > -1) { 94 | index = recursiveIndex; 95 | } 96 | } 97 | } 98 | return index; 99 | } 100 | 101 | /** 102 | * Recursively search subfolders and return the parent of the given object id. 103 | * If this is the object id of self, return nil. If the object is not found, return nil. 104 | * 105 | */ 106 | - (id) findParentOfObjectWith:(NSString *) objId { 107 | id parentId = nil; 108 | for (id entry in contents) { 109 | if ([[NSString stringWithFormat:@"%ld", (long) entry] isEqualToString:objId]) { 110 | parentId = self; 111 | } else if ([entry isKindOfClass:[CRCSavedRequestFolder class]]) { 112 | id recursiveParentId = [((CRCSavedRequestFolder *)entry) findParentOfObjectWith:objId]; 113 | if (recursiveParentId) { 114 | parentId = recursiveParentId; 115 | } 116 | } 117 | } 118 | return parentId; 119 | } 120 | 121 | -(id)init { 122 | if (self = [super init]) { 123 | contents = [[NSMutableArray alloc] init]; 124 | } 125 | return self; 126 | } 127 | 128 | - (void)encodeWithCoder:(NSCoder *)coder { 129 | [coder encodeObject:self.name forKey:@"name"]; 130 | [coder encodeObject:self.contents forKey:@"contents"]; 131 | } 132 | 133 | - (id) initWithCoder:(NSCoder *)coder { 134 | if (self = [super init]) { 135 | name = [coder decodeObjectForKey:@"name"]; 136 | contents = [coder decodeObjectForKey:@"contents"]; 137 | } 138 | return self; 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /request/NSData+gzip.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+gzip.h 3 | // CocoaRestClient 4 | // 5 | // Created by Eric Broska on 1/30/13. 6 | // 7 | // 8 | #import 9 | 10 | @interface NSData (gzip) 11 | 12 | /* 13 | * Returns gzip compressed data 14 | * (max compression, adds gzip headers) 15 | */ 16 | - (NSData *)gzipped; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /request/NSData+gzip.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+gzip.m 3 | // CocoaRestClient 4 | // 5 | // Created by Eric Broska on 1/30/13. 6 | // 7 | #include 8 | #import "NSData+gzip.h" 9 | 10 | @implementation NSData (gzip) 11 | 12 | - (NSData *)gzipped 13 | { 14 | if ([self length] == 0) { 15 | return nil; 16 | } 17 | z_stream stream = {0}; 18 | stream.avail_in = [self length]; 19 | stream.next_in = (unsigned char *)[self bytes]; 20 | /* 21 | * (15+16) means: max window size(15) + write gzip headers(16) 22 | */ 23 | int error = deflateInit2(&stream, Z_BEST_COMPRESSION, Z_DEFLATED, (15+16), MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY); 24 | if (Z_OK != error) { 25 | NSLog(@"zlib's deflateInit2() error response: %d\n", error); 26 | return nil; 27 | } 28 | /* 29 | * > In this case [Z_FINISH], avail_out must be at least 0.1% larger than avail_in plus 12 bytes. 30 | * @ http://www.gzip.org/zlib/manual.html 31 | */ 32 | NSMutableData *result = [NSMutableData dataWithLength: [self length] * 1.01 + 12]; 33 | 34 | while (Z_OK == error) { 35 | stream.next_out = [result mutableBytes] + stream.total_out; 36 | stream.avail_out = [result length] - stream.total_out; 37 | error = deflate(&stream, Z_FINISH); 38 | } 39 | if (error != Z_STREAM_END) { 40 | NSLog(@"zlib's deflate() error response: %d\n", error); 41 | return nil; 42 | } 43 | deflateEnd(&stream); 44 | result.length = stream.total_out; 45 | 46 | return result; 47 | } 48 | 49 | @end 50 | -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-1-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-1-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-1.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-1.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-1_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-1_large.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-2-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-2-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-2.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-2.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-2_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-2_large.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-3-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-3-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-3.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-3.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-3_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-3_large.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-4-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-4-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-4.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-4.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-4_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-4_large.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-5-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-5-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-5.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-5.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-5_large.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-5_large.jpg -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-6-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-6-large.png -------------------------------------------------------------------------------- /screenshots/cocoa-rest-client-7-large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mmattozzi/cocoa-rest-client/51e0e7540fa4d0c814799243558b685915a6c5dc/screenshots/cocoa-rest-client-7-large.png -------------------------------------------------------------------------------- /view/ACEView+TouchBarExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // ACEView+TouchBarExtension.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/26/18. 6 | // 7 | 8 | #import "ACEWebView.h" 9 | #import 10 | 11 | @interface ACEWebView (ACEViewTouchBarExtension) 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /view/ACEView+TouchBarExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // ACEView+TouchBarExtension.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/26/18. 6 | // 7 | 8 | #import "ACEView+TouchBarExtension.h" 9 | 10 | @implementation ACEWebView (ACEViewTouchBarExtension) 11 | 12 | - (NSTouchBar *) makeTouchBar { 13 | NSWindow *window = [self window]; 14 | NSTouchBar *touchBar = [[window windowController] makeTouchBar]; 15 | return touchBar; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /view/CRCDrawerView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCDrawerView.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/16/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class MainWindowController; 12 | 13 | @interface CRCDrawerView : NSView 14 | 15 | @property (weak, nonatomic) IBOutlet MainWindowController *mainWindowController; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /view/CRCDrawerView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCDrawerView.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 1/16/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "CRCDrawerView.h" 10 | #import "MainWindowController.h" 11 | #import "CocoaRestClientAppDelegate.h" 12 | 13 | @implementation CRCDrawerView 14 | 15 | @synthesize mainWindowController; 16 | 17 | - (id)initWithFrame:(NSRect)frame 18 | { 19 | self = [super initWithFrame:frame]; 20 | if (self) { 21 | // Initialization code here. 22 | } 23 | 24 | return self; 25 | } 26 | 27 | - (void)drawRect:(NSRect)dirtyRect 28 | { 29 | // Drawing code here. 30 | [super drawRect:dirtyRect]; 31 | } 32 | 33 | - (NSDragOperation)draggingEntered:(id )sender { 34 | NSPasteboard *pboard; 35 | NSDragOperation sourceDragMask; 36 | 37 | sourceDragMask = [sender draggingSourceOperationMask]; 38 | pboard = [sender draggingPasteboard]; 39 | 40 | if ( [[pboard types] containsObject:NSFilenamesPboardType] ) { 41 | if (sourceDragMask & NSDragOperationCopy) { 42 | return NSDragOperationCopy; 43 | } 44 | } 45 | return NSDragOperationNone; 46 | } 47 | 48 | - (BOOL)performDragOperation:(id )sender { 49 | NSPasteboard *pboard; 50 | NSDragOperation sourceDragMask; 51 | 52 | sourceDragMask = [sender draggingSourceOperationMask]; 53 | pboard = [sender draggingPasteboard]; 54 | 55 | if ( [[pboard types] containsObject:NSFilenamesPboardType] ) { 56 | NSArray *files = [pboard propertyListForType:NSFilenamesPboardType]; 57 | 58 | if (sourceDragMask & NSDragOperationCopy) { 59 | NSMutableArray *loadedRequests = [[NSMutableArray alloc] init]; 60 | 61 | for (id file in files) { 62 | @try { 63 | [loadedRequests addObjectsFromArray:[NSKeyedUnarchiver unarchiveObjectWithFile:file]]; 64 | } 65 | @catch (NSException *exception) { 66 | [mainWindowController.appDelegate invalidFileAlert]; 67 | } 68 | } 69 | 70 | if ([loadedRequests count] > 0) { 71 | [mainWindowController.appDelegate importRequestsFromArray:loadedRequests]; 72 | } else { 73 | [mainWindowController.appDelegate invalidFileAlert]; 74 | } 75 | 76 | return YES; 77 | } 78 | } 79 | 80 | return NO; 81 | } 82 | 83 | -(void)keyDown:(NSEvent *)theEvent { 84 | NSLog(@"Drawer got event with keycode: %hu", [theEvent keyCode]); 85 | // Backspace or delete key 86 | if ([theEvent keyCode] == 51 || [theEvent keyCode] == 117) { 87 | [[NSNotificationCenter defaultCenter] postNotificationName:@"deleteDrawerRow" 88 | object:theEvent 89 | userInfo:@{@"sender":self}]; 90 | } else if ([theEvent keyCode] == 53) { 91 | [[NSNotificationCenter defaultCenter] postNotificationName:@"deselectSavedRequest" 92 | object:theEvent 93 | userInfo:@{@"sender":self}]; 94 | } else { 95 | [super keyDown:theEvent]; 96 | } 97 | } 98 | 99 | @end 100 | -------------------------------------------------------------------------------- /view/CRCHTTPHeaderCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // CRCHTTPHeaderCell.h 3 | // CocoaRestClient 4 | // 5 | // Created by Eric Broska on 2/12/13. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface CRCHTTPHeaderCell : NSComboBoxCell 12 | 13 | - (void)removeSelfFromDefaults; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /view/CRCHTTPHeaderCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // CRCHTTPHeaderCell.m 3 | // CocoaRestClient 4 | // 5 | // Created by Eric Broska on 2/12/13. 6 | // 7 | // 8 | 9 | #import "CRCHTTPHeaderCell.h" 10 | 11 | #define kCRCHeadersUserDefaultsKey @"kCRCHeadersUserDefaultsKey" 12 | static NSMutableArray *_CRCHeaders = nil; 13 | 14 | @interface CRCHTTPHeaderCell (Private) 15 | 16 | - (void)valueDidChanged:(NSNotification *)notification; 17 | - (void)updateHeadersListInDefaults; 18 | 19 | @end 20 | 21 | @implementation CRCHTTPHeaderCell 22 | 23 | + (void)initialize 24 | { 25 | [super initialize]; 26 | 27 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 28 | if ([defaults objectForKey: kCRCHeadersUserDefaultsKey]) { 29 | _CRCHeaders = [[defaults objectForKey: kCRCHeadersUserDefaultsKey] mutableCopy]; 30 | } else { 31 | _CRCHeaders = [[[NSBundle mainBundle] objectForInfoDictionaryKey: kCRCHeadersUserDefaultsKey] mutableCopy]; 32 | } 33 | } 34 | 35 | - (id)initWithCoder:(NSCoder *)aDecoder 36 | { 37 | if ((self=[super initWithCoder: aDecoder])) { 38 | [self addItemsWithObjectValues: _CRCHeaders]; 39 | } 40 | 41 | [[NSNotificationCenter defaultCenter] addObserver: self 42 | selector: @selector(valueDidChanged:) 43 | name: NSControlTextDidEndEditingNotification 44 | object: [self controlView]]; 45 | return (self); 46 | } 47 | 48 | - (void)updateHeaderListInDefaults 49 | { 50 | NSMutableArray *tmp = [_CRCHeaders mutableCopy]; 51 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 52 | 53 | NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; 54 | [defaults setObject: tmp forKey: kCRCHeadersUserDefaultsKey]; 55 | [defaults synchronize]; 56 | }); 57 | } 58 | 59 | - (void)valueDidChanged:(NSNotification *)notification 60 | { 61 | /* We only want to deal with CRCHTTPHeadersComboBoxCells */ 62 | if ( ! [[[notification object] selectedCell] isKindOfClass: [self class]]) { 63 | return; 64 | } 65 | /* 66 | * Well, it's a dirty hack to get the _right_ value from the cell, 67 | * because [self objectValue] returns a *last selected* item's value, 68 | * not just entered one's. 69 | */ 70 | 71 | // NSString *new_value = [[[notification object] selectedCell] objectValue]; 72 | // @synchronized (_CRCHeaders) { 73 | // if ( ! ([new_value isEqualToString: @"Key"] || [_CRCHeaders containsObject: new_value])) { 74 | // [_CRCHeaders addObject: new_value]; 75 | // } 76 | // } 77 | // 78 | // [self updateHeadersListInDefaults]; 79 | // 80 | // [self removeAllItems]; 81 | // [self addItemsWithObjectValues: _CRCHeaders]; 82 | // [self selectItemWithObjectValue: new_value]; 83 | } 84 | 85 | - (void)removeSelfFromDefaults 86 | { 87 | @synchronized (_CRCHeaders) { 88 | [_CRCHeaders removeObject: self.objectValue]; 89 | } 90 | [self updateHeadersListInDefaults]; 91 | } 92 | @end 93 | -------------------------------------------------------------------------------- /view/CRCTopView.h: -------------------------------------------------------------------------------- 1 | 2 | #import 3 | 4 | 5 | @interface CRCTopView : NSView { 6 | NSGradient *_bgGradient; 7 | NSBezierPath *line; 8 | } 9 | 10 | @end 11 | -------------------------------------------------------------------------------- /view/CRCTopView.m: -------------------------------------------------------------------------------- 1 | #import "CRCTopView.h" 2 | 3 | 4 | @implementation CRCTopView 5 | 6 | 7 | - (instancetype)initWithFrame:(NSRect)frame 8 | { 9 | self = [super initWithFrame:frame]; 10 | if (self) { 11 | 12 | [[NSNotificationCenter defaultCenter]addObserver:self 13 | selector:@selector(systemTintDidChange:) 14 | name:NSControlTintDidChangeNotification 15 | object:nil]; 16 | [self drawGradient]; 17 | 18 | } 19 | return self; 20 | } 21 | 22 | - (void)awakeFromNib { 23 | [[NSNotificationCenter defaultCenter]addObserver:self 24 | selector:@selector(systemTintDidChange:) 25 | name:NSControlTintDidChangeNotification 26 | object:nil]; 27 | [self drawGradient]; 28 | } 29 | 30 | - (void)drawGradient { 31 | NSColor *tintColor = nil; 32 | NSColor *tintDarkerColor = nil; 33 | if ([[self identifier] isEqualToString:@"topview"]) { 34 | tintColor = [[NSColor colorForControlTint:[NSColor currentControlTint]]colorUsingColorSpaceName:NSDeviceRGBColorSpace]; 35 | tintDarkerColor = [NSColor colorWithRed:tintColor.redComponent - 0.2 36 | green:tintColor.greenComponent - 0.2 37 | blue:tintColor.blueComponent - 0.2 38 | alpha:1]; 39 | } else { 40 | tintColor = [NSColor colorWithRed:0.95 green:0.95 blue:0.95 alpha:1.0]; 41 | tintDarkerColor = [NSColor colorWithRed:1.0 green:0.2 blue:1.0 alpha:1.0]; 42 | } 43 | _bgGradient = [[NSGradient alloc]initWithStartingColor:tintDarkerColor 44 | endingColor:tintColor]; 45 | line = [[NSBezierPath alloc] init]; 46 | [self setNeedsDisplay:YES]; 47 | } 48 | 49 | - (BOOL) isOpaque 50 | { 51 | return NO; 52 | } 53 | 54 | - (void)drawRect:(NSRect)dirtyRect { 55 | 56 | NSString *osxMode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; 57 | if (! [osxMode isEqualToString:@"Dark"]) { 58 | [_bgGradient drawInRect:self.bounds angle:90]; 59 | if ([[self identifier] isEqualToString:@"statusbar"]) { 60 | [[NSColor darkGrayColor] set]; 61 | [line stroke]; 62 | [line setLineWidth:1.0]; 63 | NSPoint start; 64 | start.x = self.bounds.origin.x; 65 | start.y = self.bounds.origin.y + self.bounds.size.height; 66 | NSPoint end; 67 | end.x = self.bounds.origin.x + self.bounds.size.width; 68 | end.y = self.bounds.origin.y + self.bounds.size.height; 69 | [line moveToPoint:start]; 70 | [line lineToPoint:end]; 71 | [line closePath]; 72 | } 73 | } else { 74 | [[NSColor clearColor] set]; 75 | NSRectFill(dirtyRect); 76 | } 77 | } 78 | 79 | - (void)systemTintDidChange:(NSNotification*)not { 80 | [self drawGradient]; 81 | } 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /view/DMSlidingTabItemView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DMSlidingTabItemView.h 3 | // DMSlidingTabView 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // Copyright © 2016 Diego Massanti. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DMSlidingTabViewItemProtocol.h" 11 | 12 | @interface DMSlidingTabItemView : NSView 13 | 14 | @property (nonatomic) IBInspectable NSString *tabTitle; 15 | @property NSLayoutConstraint *xPosConstraint; 16 | @property NSUInteger indexInTabSelector; 17 | @property NSSegmentedControl *parentTabSelector; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /view/DMSlidingTabItemView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DMSlidingTabItemView.m 3 | // DMSlidingTabView 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // Copyright © 2016 Diego Massanti. All rights reserved. 7 | // 8 | 9 | #import "DMSlidingTabItemView.h" 10 | 11 | @implementation DMSlidingTabItemView 12 | 13 | /*- (BOOL)wantsLayer { 14 | return YES; 15 | }*/ 16 | 17 | @synthesize tabTitle = _tabTitle; 18 | @synthesize indexInTabSelector; 19 | @synthesize parentTabSelector; 20 | 21 | - (void) setTabTitle:(NSString *)aTabTitle { 22 | if (aTabTitle) { 23 | _tabTitle = aTabTitle; 24 | [parentTabSelector setLabel:_tabTitle forSegment:indexInTabSelector]; 25 | } 26 | } 27 | 28 | - (NSString *) getTabTitle { 29 | return _tabTitle; 30 | } 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /view/DMSlidingTabView.h: -------------------------------------------------------------------------------- 1 | // 2 | // DMSlidingTabView.h 3 | // DMSlidingTabView 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // Copyright © 2016 Diego Massanti. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "DMSlidingTabViewItemProtocol.h" 11 | #import "DMSlidingTabItemView.h" 12 | #import "CRCconstants.h" 13 | 14 | IB_DESIGNABLE 15 | @interface DMSlidingTabView : NSView { 16 | NSSegmentedControl *tabSelector; 17 | NSTextField *controlTitle; 18 | NSMutableArray *tabViewItems; 19 | NSUInteger selectedTabIdx; 20 | NSArray *xConstraints; 21 | } 22 | 23 | @property NSInteger selectedTabIndex; 24 | @property IBInspectable NSString *title; 25 | 26 | - (void)addItem:(id)item; 27 | - (void)addItems:(NSArray*)items; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /view/DMSlidingTabView.m: -------------------------------------------------------------------------------- 1 | // 2 | // DMSlidingTabView.m 3 | // DMSlidingTabView 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // Copyright © 2016 Diego Massanti. All rights reserved. 7 | // 8 | 9 | #import "DMSlidingTabView.h" 10 | #import 11 | @implementation DMSlidingTabView 12 | @synthesize title; 13 | - (instancetype)initWithFrame:(NSRect)frame 14 | { 15 | self = [super initWithFrame:frame]; 16 | if (self) { 17 | [self initializeLayout]; 18 | } 19 | return self; 20 | } 21 | - (instancetype)initWithCoder:(NSCoder *)coder 22 | { 23 | self = [super initWithCoder:coder]; 24 | if (self) { 25 | [self initializeLayout]; 26 | } 27 | return self; 28 | } 29 | 30 | - (void)initializeLayout { 31 | controlTitle = [[NSTextField alloc]init]; 32 | controlTitle.editable = NO; 33 | controlTitle.font = [NSFont systemFontOfSize:18]; 34 | // controlTitle.textColor = [NSColor colorWithRed:0 green:0 blue:0 alpha:0.3]; 35 | controlTitle.bezeled = NO; 36 | controlTitle.drawsBackground = NO; 37 | controlTitle.selectable = NO; 38 | tabSelector = [[NSSegmentedControl alloc]init]; 39 | tabViewItems = [NSMutableArray array]; 40 | xConstraints = [NSArray array]; 41 | [self addSubview:tabSelector]; 42 | [self addSubview:controlTitle]; 43 | #if TARGET_INTERFACE_BUILDER 44 | tabSelector.segmentCount = 3; 45 | for (int i = 0; i < tabSelector.segmentCount; i++) { 46 | [tabSelector setLabel:@"Test Label" forSegment:i]; 47 | //self.title = @"Test Title"; 48 | } 49 | [self setupConstraints]; 50 | #else 51 | tabSelector.segmentCount = 0; 52 | #endif 53 | 54 | [tabSelector setSegmentStyle:NSSegmentStyleTexturedRounded]; 55 | //tabSelector.selectedSegment = 0; 56 | self.selectedTabIndex = -1; 57 | tabSelector.translatesAutoresizingMaskIntoConstraints = NO; 58 | controlTitle.translatesAutoresizingMaskIntoConstraints = NO; 59 | [tabSelector setTarget:self]; 60 | [tabSelector setAction:@selector(selectedTabDidChange:)]; 61 | } 62 | 63 | 64 | 65 | #pragma mark -- Items 66 | 67 | - (void)addItem:(id)item { 68 | [tabViewItems addObject:item]; 69 | } 70 | 71 | - (void)addItems:(NSArray*)items { 72 | [items enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 73 | [self addItem:obj]; 74 | }]; 75 | [self updateTabs]; 76 | } 77 | 78 | - (void)updateTabs { 79 | tabSelector.segmentCount = tabViewItems.count; 80 | NSMutableArray *xPosCons = [NSMutableArray arrayWithCapacity:tabViewItems.count]; 81 | [tabViewItems enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 82 | DMSlidingTabItemView *item = (DMSlidingTabItemView*)obj; 83 | [tabSelector setLabel:item.tabTitle forSegment:idx]; 84 | item.indexInTabSelector = idx; 85 | item.parentTabSelector = tabSelector; 86 | item.translatesAutoresizingMaskIntoConstraints = NO; 87 | [self addSubview:item]; 88 | 89 | NSLayoutConstraint *topSpace = [NSLayoutConstraint constraintWithItem:item 90 | attribute:NSLayoutAttributeTop 91 | relatedBy:NSLayoutRelationEqual 92 | toItem:tabSelector 93 | attribute:NSLayoutAttributeBottom 94 | multiplier:1 constant:10]; 95 | NSLayoutConstraint *bottomSpace = [NSLayoutConstraint constraintWithItem:item 96 | attribute:NSLayoutAttributeBottom 97 | relatedBy:NSLayoutRelationEqual 98 | toItem:self 99 | attribute:NSLayoutAttributeBottom 100 | multiplier:1 constant:0]; 101 | NSLayoutConstraint *equalWidth = [NSLayoutConstraint constraintWithItem:item 102 | attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual 103 | toItem:self 104 | attribute:NSLayoutAttributeWidth 105 | multiplier:1 constant:0]; 106 | CGFloat leftSpaceConstant = 0; 107 | if (idx > 0) leftSpaceConstant = 4000; 108 | 109 | NSLayoutConstraint *leftSpace = [NSLayoutConstraint constraintWithItem:item 110 | attribute:NSLayoutAttributeLeft 111 | relatedBy:NSLayoutRelationEqual 112 | toItem:self 113 | attribute:NSLayoutAttributeLeft 114 | multiplier:1 constant:leftSpaceConstant]; 115 | [xPosCons addObject:leftSpace]; 116 | item.xPosConstraint = leftSpace; 117 | item.hidden = idx > 0 ? YES : NO; 118 | 119 | [self addConstraint:topSpace]; 120 | [self addConstraint:bottomSpace]; 121 | [self addConstraint:equalWidth]; 122 | [self addConstraint:leftSpace]; 123 | 124 | }]; 125 | [self setNeedsDisplay:YES]; 126 | [self setNeedsLayout:YES]; 127 | xConstraints = [NSArray arrayWithArray:xPosCons]; 128 | tabSelector.selectedSegment = 0; 129 | [self selectedTabDidChange:tabSelector]; 130 | 131 | } 132 | 133 | #pragma mark -- Segment Selection 134 | 135 | - (void)selectedTabDidChange:(NSSegmentedControl*)sender { 136 | if (self.selectedTabIndex == sender.selectedSegment) return; 137 | DMSlidingTabItemView *itemToHide; 138 | if (self.selectedTabIndex > -1) { 139 | itemToHide = [tabViewItems objectAtIndex:self.selectedTabIndex]; 140 | } 141 | float direction = self.selectedTabIndex > sender.selectedSegment ? self.bounds.size.width : -(self.bounds.size.width); 142 | DMSlidingTabItemView *itemToShow = [tabViewItems objectAtIndex:sender.selectedSegment]; 143 | itemToShow.xPosConstraint.constant = sender.selectedSegment > self.selectedTabIndex ? self.frame.size.width : -(self.frame.size.width); 144 | itemToShow.hidden = NO; 145 | [NSAnimationContext runAnimationGroup:^(NSAnimationContext * _Nonnull context) { 146 | context.duration = [[NSUserDefaults standardUserDefaults]boolForKey:DISABLE_ANIMATIONS] ? 0.0f : 0.15f; 147 | context.allowsImplicitAnimation = YES; 148 | context.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 149 | itemToHide.xPosConstraint.animator.constant = direction; 150 | itemToShow.xPosConstraint.animator.constant = 0; 151 | } completionHandler:^{ 152 | itemToHide.hidden = YES; 153 | 154 | }]; 155 | self.selectedTabIndex = sender.selectedSegment; 156 | 157 | 158 | /*[tabViewItems enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 159 | DMSlidingTabItemView *item = (DMSlidingTabItemView*)obj; 160 | if ([tabViewItems indexOfObject:item] != sender.selectedSegment && [tabViewItems indexOfObject:item] == self.selectedTabIndex) { 161 | // Item has to dissapear 162 | } 163 | item.hidden = [tabViewItems indexOfObject:item] == sender.selectedSegment ? NO : YES; 164 | }];*/ 165 | } 166 | - (void)setTitle:(NSString *)t { 167 | title = t; 168 | controlTitle.stringValue = title.uppercaseString; 169 | } 170 | 171 | - (NSString*)title { 172 | return title; 173 | } 174 | 175 | - (void)awakeFromNib { 176 | controlTitle.stringValue = self.title; 177 | [self setupConstraints]; 178 | } 179 | 180 | - (void)setupConstraints { 181 | NSArray *constraints = 182 | [NSLayoutConstraint constraintsWithVisualFormat:@"|-0-[tabSelector]->=10-[controlTitle(<=120)]-0-|" 183 | options:NSLayoutFormatAlignAllCenterY 184 | metrics:nil 185 | views:@{@"tabSelector": tabSelector, @"controlTitle": controlTitle} 186 | 187 | 188 | ]; 189 | 190 | NSLayoutConstraint *c2 = [NSLayoutConstraint constraintWithItem:tabSelector 191 | attribute:NSLayoutAttributeTop 192 | relatedBy:NSLayoutRelationEqual 193 | toItem:self 194 | attribute:NSLayoutAttributeTop multiplier:1 constant:0]; 195 | //[NSLayoutConstraint activateConstraints:constraints]; // NOT AVAILABLE IN 10.9 196 | [self addConstraints:constraints]; 197 | [self addConstraint:c2]; 198 | [self invalidateIntrinsicContentSize]; 199 | } 200 | 201 | - (void)drawRect:(NSRect)dirtyRect { 202 | [super drawRect:dirtyRect]; 203 | [[NSGraphicsContext currentContext] saveGraphicsState]; 204 | [[NSColor colorWithRed:0 green:0 blue:0 alpha:0.1]set]; 205 | 206 | NSBezierPath * dividerLine = [[NSBezierPath alloc]init]; 207 | [dividerLine moveToPoint:NSMakePoint(0, self.bounds.size.height -27)]; 208 | [dividerLine lineToPoint:NSMakePoint(self.bounds.size.width, self.bounds.size.height -27)]; 209 | [dividerLine setLineWidth:0.5]; 210 | [dividerLine stroke]; 211 | [[NSGraphicsContext currentContext] restoreGraphicsState]; 212 | } 213 | 214 | @end 215 | -------------------------------------------------------------------------------- /view/DMSlidingTabViewItemProtocol.h: -------------------------------------------------------------------------------- 1 | // 2 | // DMSlidingTabViewItem.h 3 | // DMSlidingTabView 4 | // 5 | // Created by Diego Massanti on 3/9/16. 6 | // Copyright © 2016 Diego Massanti. All rights reserved. 7 | // 8 | 9 | #ifndef DMSlidingTabViewItem_h 10 | #define DMSlidingTabViewItem_h 11 | 12 | @protocol DMSlidingTabViewItem 13 | 14 | @required 15 | @property (nonatomic) NSString *tabTitle; 16 | 17 | @end 18 | #endif /* DMSlidingTabViewItem_h */ 19 | -------------------------------------------------------------------------------- /view/FastSearchSavedRequestTextCellView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FastSearchSavedRequestTextFieldCell.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 2/28/17. 6 | // 7 | // 8 | 9 | #import 10 | 11 | @interface FastSearchSavedRequestTextCellView : NSTableCellView 12 | 13 | @property (nonatomic, retain) IBOutlet NSTextField *detailTextField; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /view/FastSearchSavedRequestTextCellView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FastSearchSavedRequestTextFieldCell.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 2/28/17. 6 | // 7 | // 8 | 9 | #import "FastSearchSavedRequestTextCellView.h" 10 | 11 | @implementation FastSearchSavedRequestTextCellView 12 | 13 | @synthesize detailTextField; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /view/HighlightingTypeManager.h: -------------------------------------------------------------------------------- 1 | // 2 | // HighlightingTypeManager.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 2/8/15. 6 | // 7 | // 8 | 9 | #import 10 | #import "ACEView/ACEView.h" 11 | 12 | @interface HighlightingTypeManager : NSObject { 13 | ACEView *view; 14 | NSDictionary *typeMapping; 15 | } 16 | 17 | - (HighlightingTypeManager *) initWithView:(ACEView*) view; 18 | - (void) setModeForMimeType:(NSString*) mimeType; 19 | 20 | @end 21 | -------------------------------------------------------------------------------- /view/HighlightingTypeManager.m: -------------------------------------------------------------------------------- 1 | // 2 | // HighlightingTypeManager.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 2/8/15. 6 | // 7 | // 8 | 9 | #import "HighlightingTypeManager.h" 10 | #import "ContentTypes.h" 11 | 12 | @implementation HighlightingTypeManager 13 | 14 | - (HighlightingTypeManager *) initWithView:(ACEView*) aceView { 15 | self->view = aceView; 16 | 17 | typeMapping = @{ 18 | @"application/json": [NSNumber numberWithInteger:ACEModeJSON], 19 | @"text/xml": [NSNumber numberWithInteger:ACEModeXML], 20 | @"application/xml": [NSNumber numberWithInteger:ACEModeXML], 21 | @"application/javascript": [NSNumber numberWithInteger:ACEModeJavaScript], 22 | @"text/javascript": [NSNumber numberWithInteger:ACEModeJavaScript], 23 | @"text/html": [NSNumber numberWithInteger:ACEModeHTML], 24 | @"application/atom+xml": [NSNumber numberWithInteger:ACEModeXML], 25 | @"application/rss+xml": [NSNumber numberWithInteger:ACEModeXML], 26 | @"text/css": [NSNumber numberWithInteger:ACEModeCSS], 27 | @"application/soap+xml": [NSNumber numberWithInteger:ACEModeXML], 28 | @"application/xml-dtd": [NSNumber numberWithInteger:ACEModeXML], 29 | @"text/yaml": [NSNumber numberWithInteger:ACEModeYAML], 30 | @"application/x-yaml": [NSNumber numberWithInteger:ACEModeYAML], 31 | @"application/yaml": [NSNumber numberWithInteger:ACEModeYAML] 32 | }; 33 | 34 | return self; 35 | } 36 | 37 | - (void) setModeForMimeType:(NSString*) mimeType { 38 | NSNumber *mode = [typeMapping valueForKey:mimeType]; 39 | if (mode) { 40 | [self->view setMode:[mode intValue]]; 41 | } else if ([[ContentTypes sharedContentTypes] isJson:mimeType]) { 42 | [self->view setMode:ACEModeJSON]; 43 | } else if ([[ContentTypes sharedContentTypes] isXml:mimeType]) { 44 | [self->view setMode:ACEModeXML]; 45 | } else { 46 | [self->view setMode:ACEModeText]; 47 | } 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /view/NSTextView+TouchBarExtension.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextView+TouchBarExtension.h 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/26/18. 6 | // 7 | 8 | #import 9 | 10 | @interface NSTextView (TouchBarExtension) 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /view/NSTextView+TouchBarExtension.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSTextView+TouchBarExtension.m 3 | // CocoaRestClient 4 | // 5 | // Created by Mike Mattozzi on 3/26/18. 6 | // 7 | 8 | #import "NSTextView+TouchBarExtension.h" 9 | 10 | @implementation NSTextView (TouchBarExtension) 11 | 12 | - (NSTouchBar *) makeTouchBar { 13 | NSWindow *window = [self window]; 14 | NSTouchBar *touchBar = [window makeTouchBar]; 15 | return touchBar; 16 | } 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /view/TabbingTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // TabbingTableView.h 3 | // CocoaRestClient 4 | // 5 | // This is a subclass of NSTableView that remembers the last text movement keypress 6 | // after a value is edited. This allows the TableView to keep track of whether the edit 7 | // ended with the return key, the tab key, or some other key. 8 | // 9 | // Created by Michael Mattozzi on 2/25/12. 10 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 11 | // 12 | 13 | #import 14 | 15 | @interface TabbingTableView : NSTableView { 16 | int lastTextMovement; 17 | SEL textDidEndEditingAction; 18 | } 19 | 20 | - (int) getLastTextMovement; 21 | - (void) setTextDidEndEditingAction: (SEL)action; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /view/TabbingTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // TabbingTableView.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 2/25/12. 6 | // Copyright (c) 2012 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "TabbingTableView.h" 10 | #import "TableRowAndColumn.h" 11 | 12 | @implementation TabbingTableView 13 | 14 | // Remember the key the user pressed to end the editing action 15 | - (void) textDidEndEditing: (NSNotification *) notification { 16 | int editedColumn = [self editedColumn]; 17 | int editedRow = [self editedRow]; 18 | NSTableColumn *currentColumn = [[self tableColumns] objectAtIndex:editedColumn]; 19 | NSDictionary *userInfo = [notification userInfo]; 20 | lastTextMovement = [[userInfo valueForKey:@"NSTextMovement"] intValue]; 21 | [super textDidEndEditing: notification]; 22 | if (textDidEndEditingAction) { 23 | TableRowAndColumn *tableRowAndColumn = [[TableRowAndColumn alloc] init]; 24 | tableRowAndColumn.column = currentColumn; 25 | tableRowAndColumn.row = editedRow; 26 | [[self delegate] performSelector:textDidEndEditingAction withObject:tableRowAndColumn]; 27 | } 28 | } 29 | 30 | - (int) getLastTextMovement { 31 | return lastTextMovement; 32 | } 33 | 34 | - (void) setTextDidEndEditingAction: (SEL)action { 35 | textDidEndEditingAction = action; 36 | } 37 | 38 | - (void)keyDown:(NSEvent *)theEvent { 39 | // Backspace or delete key 40 | if ([theEvent keyCode] == 51 || [theEvent keyCode] == 117) { 41 | NSString *identifier = [self identifier]; 42 | NSDictionary *payload = @{@"sender":self, @"identifier": identifier}; 43 | [[NSNotificationCenter defaultCenter] postNotificationName:@"deleteTableRow" 44 | object:theEvent userInfo:payload]; 45 | } else { 46 | [super keyDown:theEvent]; 47 | } 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /view/TableRowAndColumn.h: -------------------------------------------------------------------------------- 1 | // 2 | // TableRowAndColumn.h 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 6/10/13. 6 | // Copyright (c) 2013 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface TableRowAndColumn : NSObject { 12 | NSTableColumn *column; 13 | int row; 14 | } 15 | 16 | @property (nonatomic, strong) NSTableColumn *column; 17 | @property (nonatomic, assign) int row; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /view/TableRowAndColumn.m: -------------------------------------------------------------------------------- 1 | // 2 | // TableRowAndColumn.m 3 | // CocoaRestClient 4 | // 5 | // Created by Michael Mattozzi on 6/10/13. 6 | // Copyright (c) 2013 Michael Mattozzi. All rights reserved. 7 | // 8 | 9 | #import "TableRowAndColumn.h" 10 | 11 | @implementation TableRowAndColumn 12 | 13 | @synthesize column; 14 | @synthesize row; 15 | 16 | @end 17 | --------------------------------------------------------------------------------