From 8eee8767d1780a830af03f5c2f9fad4409215cbd Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Sat, 11 Jan 2020 14:42:28 -0500 Subject: [PATCH] Initial commit --- .gitignore | 77 ++ MongoView.xcodeproj/project.pbxproj | 468 +++++++ .../contents.xcworkspacedata | 10 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + MongoView/AppDelegate.swift | 74 ++ .../AppIcon.appiconset/Contents.json | 58 + MongoView/Assets.xcassets/Contents.json | 6 + MongoView/Base.lproj/MainMenu.xib | 449 +++++++ MongoView/Info.plist | 36 + MongoView/MongoController.swift | 37 + MongoView/MongoView.entitlements | 12 + MongoView/Node.swift | 146 +++ .../DatabaseViewController.swift | 214 ++++ .../DatabaseViewController.xib | 143 +++ .../QueryViewController.swift | 166 +++ .../View Controllers/QueryViewController.xib | 1108 +++++++++++++++++ .../ServerConnectViewController.swift | 89 ++ .../ServerConnectViewController.xib | 212 ++++ .../Windows/DatabaseWindowController.swift | 56 + .../Windows/DatabaseWindowController.xib | 31 + .../ServerConnectWindowController.swift | 27 + .../Windows/ServerConnectWindowController.xib | 31 + 22 files changed, 3458 insertions(+) create mode 100644 .gitignore create mode 100644 MongoView.xcodeproj/project.pbxproj create mode 100644 MongoView.xcworkspace/contents.xcworkspacedata create mode 100644 MongoView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 MongoView/AppDelegate.swift create mode 100644 MongoView/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 MongoView/Assets.xcassets/Contents.json create mode 100644 MongoView/Base.lproj/MainMenu.xib create mode 100644 MongoView/Info.plist create mode 100644 MongoView/MongoController.swift create mode 100644 MongoView/MongoView.entitlements create mode 100644 MongoView/Node.swift create mode 100644 MongoView/View Controllers/DatabaseViewController.swift create mode 100644 MongoView/View Controllers/DatabaseViewController.xib create mode 100644 MongoView/View Controllers/QueryViewController.swift create mode 100644 MongoView/View Controllers/QueryViewController.xib create mode 100644 MongoView/View Controllers/ServerConnectViewController.swift create mode 100644 MongoView/View Controllers/ServerConnectViewController.xib create mode 100644 MongoView/Windows/DatabaseWindowController.swift create mode 100644 MongoView/Windows/DatabaseWindowController.xib create mode 100644 MongoView/Windows/ServerConnectWindowController.swift create mode 100644 MongoView/Windows/ServerConnectWindowController.xib diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..71c8374 --- /dev/null +++ b/.gitignore @@ -0,0 +1,77 @@ +.DS_Store + +### Swift ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated +build/ +DerivedData/ + +## Various settings +*.pbxuser +!default.pbxuser +*.mode1v3 +!default.mode1v3 +*.mode2v3 +!default.mode2v3 +*.perspectivev3 +!default.perspectivev3 +xcuserdata/ + +## Other +*.moved-aside +*.xccheckout +*.xcscmblueprint + +## Obj-C/Swift specific +*.hmap +*.ipa +*.dSYM.zip +*.dSYM + +## Playgrounds +timeline.xctimeline +playground.xcworkspace + +# Swift Package Manager +# +# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. +# Packages/ +# Package.pins +.build/ + +# CocoaPods - Refactored to standalone file + +# Carthage - Refactored to standalone file + +# fastlane +# +# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the +# screenshots whenever they are needed. +# For more information about the recommended setup visit: +# https://docs.fastlane.tools/best-practices/source-control/#source-control + +fastlane/report.xml +fastlane/Preview.html +fastlane/screenshots +fastlane/test_output + +### Xcode ### +# Xcode +# +# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore + +## Build generated + +## Various settings + +## Other + +### Xcode Patch ### +*.xcodeproj/* +!*.xcodeproj/project.pbxproj +!*.xcodeproj/xcshareddata/ +!*.xcworkspace/contents.xcworkspacedata +/*.gcno diff --git a/MongoView.xcodeproj/project.pbxproj b/MongoView.xcodeproj/project.pbxproj new file mode 100644 index 0000000..a7df9f4 --- /dev/null +++ b/MongoView.xcodeproj/project.pbxproj @@ -0,0 +1,468 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 50; + objects = { + +/* Begin PBXBuildFile section */ + D60C863923CA2DD100C9DB8E /* ServerConnectWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D60C863723CA2DD100C9DB8E /* ServerConnectWindowController.swift */; }; + D60C863A23CA2DD100C9DB8E /* ServerConnectWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D60C863823CA2DD100C9DB8E /* ServerConnectWindowController.xib */; }; + D60C863F23CA2E2100C9DB8E /* ServerConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D60C863D23CA2E2100C9DB8E /* ServerConnectViewController.swift */; }; + D60C864023CA2E2100C9DB8E /* ServerConnectViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D60C863E23CA2E2100C9DB8E /* ServerConnectViewController.xib */; }; + D63CDEBE23C837DC0012D658 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDEBD23C837DC0012D658 /* AppDelegate.swift */; }; + D63CDEC023C837DD0012D658 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = D63CDEBF23C837DD0012D658 /* Assets.xcassets */; }; + D63CDEC323C837DD0012D658 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = D63CDEC123C837DD0012D658 /* MainMenu.xib */; }; + D63CDF1F23C837F10012D658 /* CLibMongoC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1623C837F10012D658 /* CLibMongoC.framework */; }; + D63CDF2023C837F10012D658 /* CLibMongoC.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1623C837F10012D658 /* CLibMongoC.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2123C837F10012D658 /* CNIOAtomics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1723C837F10012D658 /* CNIOAtomics.framework */; }; + D63CDF2223C837F10012D658 /* CNIOAtomics.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1723C837F10012D658 /* CNIOAtomics.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2323C837F10012D658 /* CNIODarwin.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1823C837F10012D658 /* CNIODarwin.framework */; }; + D63CDF2423C837F10012D658 /* CNIODarwin.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1823C837F10012D658 /* CNIODarwin.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2523C837F10012D658 /* CNIOLinux.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1923C837F10012D658 /* CNIOLinux.framework */; }; + D63CDF2623C837F10012D658 /* CNIOLinux.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1923C837F10012D658 /* CNIOLinux.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2723C837F10012D658 /* CNIOSHA1.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1A23C837F10012D658 /* CNIOSHA1.framework */; }; + D63CDF2823C837F10012D658 /* CNIOSHA1.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1A23C837F10012D658 /* CNIOSHA1.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2923C837F10012D658 /* MongoSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1B23C837F10012D658 /* MongoSwift.framework */; }; + D63CDF2A23C837F10012D658 /* MongoSwift.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1B23C837F10012D658 /* MongoSwift.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2B23C837F10012D658 /* MongoSwiftSync.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1C23C837F10012D658 /* MongoSwiftSync.framework */; }; + D63CDF2C23C837F10012D658 /* MongoSwiftSync.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1C23C837F10012D658 /* MongoSwiftSync.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2D23C837F10012D658 /* NIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1D23C837F10012D658 /* NIO.framework */; }; + D63CDF2E23C837F10012D658 /* NIO.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1D23C837F10012D658 /* NIO.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF2F23C837F10012D658 /* NIOConcurrencyHelpers.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1E23C837F10012D658 /* NIOConcurrencyHelpers.framework */; }; + D63CDF3023C837F10012D658 /* NIOConcurrencyHelpers.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D63CDF1E23C837F10012D658 /* NIOConcurrencyHelpers.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + D63CDF3723C8381A0012D658 /* Node.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDF3323C838190012D658 /* Node.swift */; }; + D63CDF3823C8381A0012D658 /* MongoController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDF3423C838190012D658 /* MongoController.swift */; }; + D63CDF3C23C838470012D658 /* DatabaseWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDF3A23C838470012D658 /* DatabaseWindowController.swift */; }; + D63CDF3D23C838470012D658 /* DatabaseWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D63CDF3B23C838470012D658 /* DatabaseWindowController.xib */; }; + D63CDF4023C839010012D658 /* QueryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDF3E23C839010012D658 /* QueryViewController.swift */; }; + D63CDF4123C839010012D658 /* QueryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D63CDF3F23C839010012D658 /* QueryViewController.xib */; }; + D63CDF4423C970C50012D658 /* DatabaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D63CDF4223C970C50012D658 /* DatabaseViewController.swift */; }; + D63CDF4523C970C50012D658 /* DatabaseViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D63CDF4323C970C50012D658 /* DatabaseViewController.xib */; }; +/* End PBXBuildFile section */ + +/* Begin PBXCopyFilesBuildPhase section */ + D63CDF3123C837F10012D658 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + D63CDF2823C837F10012D658 /* CNIOSHA1.framework in Embed Frameworks */, + D63CDF2623C837F10012D658 /* CNIOLinux.framework in Embed Frameworks */, + D63CDF2423C837F10012D658 /* CNIODarwin.framework in Embed Frameworks */, + D63CDF2A23C837F10012D658 /* MongoSwift.framework in Embed Frameworks */, + D63CDF2223C837F10012D658 /* CNIOAtomics.framework in Embed Frameworks */, + D63CDF2023C837F10012D658 /* CLibMongoC.framework in Embed Frameworks */, + D63CDF2C23C837F10012D658 /* MongoSwiftSync.framework in Embed Frameworks */, + D63CDF3023C837F10012D658 /* NIOConcurrencyHelpers.framework in Embed Frameworks */, + D63CDF2E23C837F10012D658 /* NIO.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + D60C863723CA2DD100C9DB8E /* ServerConnectWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectWindowController.swift; sourceTree = ""; }; + D60C863823CA2DD100C9DB8E /* ServerConnectWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ServerConnectWindowController.xib; sourceTree = ""; }; + D60C863D23CA2E2100C9DB8E /* ServerConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerConnectViewController.swift; sourceTree = ""; }; + D60C863E23CA2E2100C9DB8E /* ServerConnectViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ServerConnectViewController.xib; sourceTree = ""; }; + D63CDEBA23C837DC0012D658 /* MongoView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MongoView.app; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDEBD23C837DC0012D658 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + D63CDEBF23C837DD0012D658 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + D63CDEC223C837DD0012D658 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + D63CDEC423C837DD0012D658 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + D63CDEC523C837DD0012D658 /* MongoView.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MongoView.entitlements; sourceTree = ""; }; + D63CDF1623C837F10012D658 /* CLibMongoC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CLibMongoC.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1723C837F10012D658 /* CNIOAtomics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CNIOAtomics.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1823C837F10012D658 /* CNIODarwin.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CNIODarwin.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1923C837F10012D658 /* CNIOLinux.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CNIOLinux.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1A23C837F10012D658 /* CNIOSHA1.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = CNIOSHA1.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1B23C837F10012D658 /* MongoSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MongoSwift.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1C23C837F10012D658 /* MongoSwiftSync.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = MongoSwiftSync.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1D23C837F10012D658 /* NIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = NIO.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF1E23C837F10012D658 /* NIOConcurrencyHelpers.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = NIOConcurrencyHelpers.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + D63CDF3323C838190012D658 /* Node.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Node.swift; sourceTree = ""; }; + D63CDF3423C838190012D658 /* MongoController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MongoController.swift; sourceTree = ""; }; + D63CDF3A23C838470012D658 /* DatabaseWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseWindowController.swift; sourceTree = ""; }; + D63CDF3B23C838470012D658 /* DatabaseWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DatabaseWindowController.xib; sourceTree = ""; }; + D63CDF3E23C839010012D658 /* QueryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryViewController.swift; sourceTree = ""; }; + D63CDF3F23C839010012D658 /* QueryViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = QueryViewController.xib; sourceTree = ""; }; + D63CDF4223C970C50012D658 /* DatabaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseViewController.swift; sourceTree = ""; }; + D63CDF4323C970C50012D658 /* DatabaseViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DatabaseViewController.xib; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + D63CDEB723C837DC0012D658 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + D63CDF2723C837F10012D658 /* CNIOSHA1.framework in Frameworks */, + D63CDF2523C837F10012D658 /* CNIOLinux.framework in Frameworks */, + D63CDF2323C837F10012D658 /* CNIODarwin.framework in Frameworks */, + D63CDF2923C837F10012D658 /* MongoSwift.framework in Frameworks */, + D63CDF2123C837F10012D658 /* CNIOAtomics.framework in Frameworks */, + D63CDF1F23C837F10012D658 /* CLibMongoC.framework in Frameworks */, + D63CDF2B23C837F10012D658 /* MongoSwiftSync.framework in Frameworks */, + D63CDF2F23C837F10012D658 /* NIOConcurrencyHelpers.framework in Frameworks */, + D63CDF2D23C837F10012D658 /* NIO.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + D60C863B23CA2DD600C9DB8E /* Windows */ = { + isa = PBXGroup; + children = ( + D60C863723CA2DD100C9DB8E /* ServerConnectWindowController.swift */, + D60C863823CA2DD100C9DB8E /* ServerConnectWindowController.xib */, + D63CDF3A23C838470012D658 /* DatabaseWindowController.swift */, + D63CDF3B23C838470012D658 /* DatabaseWindowController.xib */, + ); + path = Windows; + sourceTree = ""; + }; + D60C863C23CA2DDD00C9DB8E /* View Controllers */ = { + isa = PBXGroup; + children = ( + D60C863D23CA2E2100C9DB8E /* ServerConnectViewController.swift */, + D60C863E23CA2E2100C9DB8E /* ServerConnectViewController.xib */, + D63CDF4223C970C50012D658 /* DatabaseViewController.swift */, + D63CDF4323C970C50012D658 /* DatabaseViewController.xib */, + D63CDF3E23C839010012D658 /* QueryViewController.swift */, + D63CDF3F23C839010012D658 /* QueryViewController.xib */, + ); + path = "View Controllers"; + sourceTree = ""; + }; + D63CDEB123C837DC0012D658 = { + isa = PBXGroup; + children = ( + D63CDEBC23C837DC0012D658 /* MongoView */, + D63CDEBB23C837DC0012D658 /* Products */, + D63CDF1523C837F10012D658 /* Frameworks */, + ); + sourceTree = ""; + }; + D63CDEBB23C837DC0012D658 /* Products */ = { + isa = PBXGroup; + children = ( + D63CDEBA23C837DC0012D658 /* MongoView.app */, + ); + name = Products; + sourceTree = ""; + }; + D63CDEBC23C837DC0012D658 /* MongoView */ = { + isa = PBXGroup; + children = ( + D63CDEBD23C837DC0012D658 /* AppDelegate.swift */, + D63CDF3423C838190012D658 /* MongoController.swift */, + D63CDF3323C838190012D658 /* Node.swift */, + D60C863B23CA2DD600C9DB8E /* Windows */, + D60C863C23CA2DDD00C9DB8E /* View Controllers */, + D63CDEBF23C837DD0012D658 /* Assets.xcassets */, + D63CDEC123C837DD0012D658 /* MainMenu.xib */, + D63CDEC423C837DD0012D658 /* Info.plist */, + D63CDEC523C837DD0012D658 /* MongoView.entitlements */, + ); + path = MongoView; + sourceTree = ""; + }; + D63CDF1523C837F10012D658 /* Frameworks */ = { + isa = PBXGroup; + children = ( + D63CDF1623C837F10012D658 /* CLibMongoC.framework */, + D63CDF1723C837F10012D658 /* CNIOAtomics.framework */, + D63CDF1823C837F10012D658 /* CNIODarwin.framework */, + D63CDF1923C837F10012D658 /* CNIOLinux.framework */, + D63CDF1A23C837F10012D658 /* CNIOSHA1.framework */, + D63CDF1B23C837F10012D658 /* MongoSwift.framework */, + D63CDF1C23C837F10012D658 /* MongoSwiftSync.framework */, + D63CDF1D23C837F10012D658 /* NIO.framework */, + D63CDF1E23C837F10012D658 /* NIOConcurrencyHelpers.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + D63CDEB923C837DC0012D658 /* MongoView */ = { + isa = PBXNativeTarget; + buildConfigurationList = D63CDEC823C837DD0012D658 /* Build configuration list for PBXNativeTarget "MongoView" */; + buildPhases = ( + D63CDEB623C837DC0012D658 /* Sources */, + D63CDEB723C837DC0012D658 /* Frameworks */, + D63CDEB823C837DC0012D658 /* Resources */, + D63CDF3123C837F10012D658 /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = MongoView; + productName = MongoView; + productReference = D63CDEBA23C837DC0012D658 /* MongoView.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + D63CDEB223C837DC0012D658 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 1130; + LastUpgradeCheck = 1130; + ORGANIZATIONNAME = Shadowfacts; + TargetAttributes = { + D63CDEB923C837DC0012D658 = { + CreatedOnToolsVersion = 11.3; + }; + }; + }; + buildConfigurationList = D63CDEB523C837DC0012D658 /* Build configuration list for PBXProject "MongoView" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = D63CDEB123C837DC0012D658; + productRefGroup = D63CDEBB23C837DC0012D658 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D63CDEB923C837DC0012D658 /* MongoView */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + D63CDEB823C837DC0012D658 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D60C864023CA2E2100C9DB8E /* ServerConnectViewController.xib in Resources */, + D63CDEC023C837DD0012D658 /* Assets.xcassets in Resources */, + D60C863A23CA2DD100C9DB8E /* ServerConnectWindowController.xib in Resources */, + D63CDF4523C970C50012D658 /* DatabaseViewController.xib in Resources */, + D63CDF3D23C838470012D658 /* DatabaseWindowController.xib in Resources */, + D63CDEC323C837DD0012D658 /* MainMenu.xib in Resources */, + D63CDF4123C839010012D658 /* QueryViewController.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + D63CDEB623C837DC0012D658 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + D63CDEBE23C837DC0012D658 /* AppDelegate.swift in Sources */, + D63CDF3823C8381A0012D658 /* MongoController.swift in Sources */, + D60C863923CA2DD100C9DB8E /* ServerConnectWindowController.swift in Sources */, + D63CDF3723C8381A0012D658 /* Node.swift in Sources */, + D60C863F23CA2E2100C9DB8E /* ServerConnectViewController.swift in Sources */, + D63CDF4423C970C50012D658 /* DatabaseViewController.swift in Sources */, + D63CDF3C23C838470012D658 /* DatabaseWindowController.swift in Sources */, + D63CDF4023C839010012D658 /* QueryViewController.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + D63CDEC123C837DD0012D658 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + D63CDEC223C837DD0012D658 /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + D63CDEC623C837DD0012D658 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + D63CDEC723C837DD0012D658 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + D63CDEC923C837DD0012D658 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = MongoView/MongoView.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = HGYVAQA9FW; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = MongoView/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.MongoView; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + D63CDECA23C837DD0012D658 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CODE_SIGN_ENTITLEMENTS = MongoView/MongoView.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = HGYVAQA9FW; + ENABLE_HARDENED_RUNTIME = YES; + INFOPLIST_FILE = MongoView/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = net.shadowfacts.MongoView; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + D63CDEB523C837DC0012D658 /* Build configuration list for PBXProject "MongoView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D63CDEC623C837DD0012D658 /* Debug */, + D63CDEC723C837DD0012D658 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + D63CDEC823C837DD0012D658 /* Build configuration list for PBXNativeTarget "MongoView" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + D63CDEC923C837DD0012D658 /* Debug */, + D63CDECA23C837DD0012D658 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = D63CDEB223C837DC0012D658 /* Project object */; +} diff --git a/MongoView.xcworkspace/contents.xcworkspacedata b/MongoView.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..e3c83be --- /dev/null +++ b/MongoView.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/MongoView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/MongoView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/MongoView.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/MongoView/AppDelegate.swift b/MongoView/AppDelegate.swift new file mode 100644 index 0000000..a8fa5ef --- /dev/null +++ b/MongoView/AppDelegate.swift @@ -0,0 +1,74 @@ +// +// AppDelegate.swift +// MongoView +// +// Created by Shadowfacts on 1/9/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa + +@NSApplicationMain +class AppDelegate: NSObject, NSApplicationDelegate { + + var windowControllers = [DatabaseWindowController]() + + var serverConnectWindowController: ServerConnectWindowController? + + func applicationDidFinishLaunching(_ aNotification: Notification) { + let wc = DatabaseWindowController() + windowControllers.append(wc) + wc.showWindow(nil) + } + + func applicationWillTerminate(_ aNotification: Notification) { + } + + func newWindow(mongoController: MongoController?, collection: DatabaseCollection? = nil, addToTabGroup: Bool = true) { + let wc = DatabaseWindowController() + wc.mongoController = mongoController + wc.initialCollection = collection + windowControllers.append(wc) + + if addToTabGroup, + let tabGroup = windowControllers.first(where: { $0.window!.isKeyWindow })?.window?.tabGroup { + tabGroup.addWindow(wc.window!) + tabGroup.selectedWindow = wc.window! + } else { + wc.showWindow(nil) + } + } + + @IBAction func newTab(_ sender: Any) { + let mongoController = windowControllers.first { $0.window!.isKeyWindow }?.mongoController + newWindow(mongoController: mongoController) + } + + @IBAction func connectToServer(_ sender: Any) { + guard serverConnectWindowController == nil else { return } + + let wc = ServerConnectWindowController() + wc.delegate = self + serverConnectWindowController = wc + wc.showWindow(nil) + } + +} + +extension AppDelegate: NSMenuItemValidation { + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + if menuItem.action == #selector(connectToServer(_:)) { + return serverConnectWindowController == nil + } + return true + } +} + +extension AppDelegate: ServerConnectViewControllerDelegate { + func connectToServer(mongoController: MongoController) { + serverConnectWindowController!.close() + serverConnectWindowController = nil + + newWindow(mongoController: mongoController, addToTabGroup: false) + } +} diff --git a/MongoView/Assets.xcassets/AppIcon.appiconset/Contents.json b/MongoView/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..2db2b1c --- /dev/null +++ b/MongoView/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "16x16", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "32x32", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "128x128", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "256x256", + "scale" : "2x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "1x" + }, + { + "idiom" : "mac", + "size" : "512x512", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MongoView/Assets.xcassets/Contents.json b/MongoView/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/MongoView/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/MongoView/Base.lproj/MainMenu.xib b/MongoView/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..0a18bad --- /dev/null +++ b/MongoView/Base.lproj/MainMenu.xib @@ -0,0 +1,449 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +DQ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/Info.plist b/MongoView/Info.plist new file mode 100644 index 0000000..f297b3e --- /dev/null +++ b/MongoView/Info.plist @@ -0,0 +1,36 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + $(PRODUCT_BUNDLE_PACKAGE_TYPE) + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + Copyright © 2020 Shadowfacts. All rights reserved. + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + NSSupportsAutomaticTermination + + NSSupportsSuddenTermination + + + diff --git a/MongoView/MongoController.swift b/MongoView/MongoController.swift new file mode 100644 index 0000000..01e7bba --- /dev/null +++ b/MongoView/MongoController.swift @@ -0,0 +1,37 @@ +// +// MongoController.swift +// MongoView +// +// Created by Shadowfacts on 1/8/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Foundation +import MongoSwift +import NIO + +class MongoController { + let connectionString: String + + var group: EventLoopGroup! + + var client: MongoClient! + + init(connectionString: String) { + self.connectionString = connectionString + } + + deinit { + try! group.syncShutdownGracefully() + cleanupMongoSwift() + } + + func setup() { + print("setting up mongo") + + group = MultiThreadedEventLoopGroup(numberOfThreads: 1) + + client = try! MongoClient(connectionString, using: group) + } + +} diff --git a/MongoView/MongoView.entitlements b/MongoView/MongoView.entitlements new file mode 100644 index 0000000..625af03 --- /dev/null +++ b/MongoView/MongoView.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.files.user-selected.read-only + + com.apple.security.network.client + + + diff --git a/MongoView/Node.swift b/MongoView/Node.swift new file mode 100644 index 0000000..c42c487 --- /dev/null +++ b/MongoView/Node.swift @@ -0,0 +1,146 @@ +// +// Node.swift +// MongoView +// +// Created by Shadowfacts on 1/9/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Foundation +import MongoSwift + +class Node { + let key: Key? + let value: BSON + + lazy private(set) var children: [Node] = { + switch value { + case let .array(array): + return array.enumerated().map { (index, val) in + Node(key: .index(index), value: val) + } + case let .document(doc): + return doc.map { (key, val) in + Node(key: .name(key), value: val) + } + default: + return [] + } + }() + + var numberOfChildren: Int { + children.count + } + + var hasChildren: Bool { + numberOfChildren > 0 + } + + init(key: Key? = nil, value: BSON) { + self.key = key + self.value = value + } + + convenience init(document: Document) { + if case let .objectId(id) = document["_id"] { + self.init(key: .objectId(id), value: .document(document)) + } else { + self.init(key: nil, value: .document(document)) + } + } +} + +extension Node { + enum Key { + case index(Int) + case name(String) + case objectId(ObjectId) + } +} + +extension Node { + static let dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.locale = .current + formatter.setLocalizedDateFormatFromTemplate("yyyy-MM-dd HH:mm:ss ZZ") + return formatter + }() + + var keyString: String { + switch key { + case nil: + return "" + case let .index(index): + return index.description + case let .name(name): + return name + case let .objectId(id): + return id.description + } + } + + var valueString: String { + switch value { + case let .double(value): + return value.description + case let .string(value): + return value + case let .document(doc): + return "(\(doc.count) field\(doc.count == 1 ? "" : "s"))" + case let .array(array): + return "(\(array.count) element\(array.count == 1 ? "" : "s"))" + case let .binary(value): + switch Binary.Subtype(rawValue: value.subtype) { + case nil: + return "(unknown binary data)" + case .generic: + return "(generic binary data)" + case .function: + return "(function binary data)" + case .binaryDeprecated: + return "(binary data)" + case .uuidDeprecated: + fallthrough + case .uuid: + return try! UUID(from: value).description + case .md5: + return "(MD5 binary data)" + case .userDefined: + return "(user defined binary data)" + } + case .undefined: + return "undefined" + case let .objectId(value): + return value.description + case let .bool(value): + return value.description + case let .datetime(value): + return value.description + case .null: + return "null" + case let .regex(value): + return try! NSRegularExpression(from: value).description + case let .dbPointer(value): + return "\(value.ref)(\(value.id))" + case let .symbol(value): + return value.description + case let .code(value): + return value.code + case let .codeWithScope(value): + return value.code + case let .int32(value): + return value.description + case let .timestamp(value): + let date = Date(timeIntervalSince1970: TimeInterval(value.timestamp)) + return Node.dateFormatter.string(from: date) + case let .int64(value): + return value.description + case let .decimal128(value): + return value.description + case .minKey: + return "(min key)" + case .maxKey: + return "(max key)" + } + } +} diff --git a/MongoView/View Controllers/DatabaseViewController.swift b/MongoView/View Controllers/DatabaseViewController.swift new file mode 100644 index 0000000..15907f8 --- /dev/null +++ b/MongoView/View Controllers/DatabaseViewController.swift @@ -0,0 +1,214 @@ +// +// DatabaseViewController.swift +// MongoView +// +// Created by Shadowfacts on 1/10/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa +import MongoSwift +import NIO + +struct DatabaseCollections { + let database: String + let collections: [String] +} + +struct DatabaseCollection { + let database: String + let name: String +} + +class DatabaseViewController: NSViewController { + + @IBOutlet weak var collectionsOutlineView: NSOutlineView! + @IBOutlet weak var detailContainerView: NSView! + + let mongoController: MongoController + + private var databaseCollections: [DatabaseCollections] = [] + private var selectedCollection: DatabaseCollection? + + private var placeholderLabel: NSTextField? + private var queryViewController: QueryViewController? + + init(mongoController: MongoController) { + self.mongoController = mongoController + + super.init(nibName: "DatabaseViewController", bundle: .main) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + mongoController.client.listDatabaseNames().flatMap { (databaseNames) -> EventLoopFuture<[DatabaseCollections]> in + let futures = databaseNames.map { (name) in + self.mongoController.client.db(name).listCollectionNames().map { (collectionNames) in + DatabaseCollections(database: name, collections: collectionNames) + } + } + return EventLoopFuture.whenAllSucceed(futures, on: futures.first!.eventLoop) + }.whenComplete { [weak self] (res) in + guard let self = self else { return } + + switch res { + case let .success(databaseCollections): + self.databaseCollections = databaseCollections + DispatchQueue.main.async { + self.collectionsOutlineView.reloadData() + } + + case let .failure(error): + fatalError("error getting database names: \(error)") + } + } + + collectionsOutlineView.dataSource = self + collectionsOutlineView.delegate = self + + collectionsOutlineView.target = self + collectionsOutlineView.doubleAction = #selector(cellDoubleClicked) + + updateDetailView() + } + + func showCollection(_ collection: DatabaseCollection) { + selectedCollection = collection + updateDetailView() + } + + private func updateDetailView() { + if let collection = selectedCollection { + if let placeholderLabel = placeholderLabel { + placeholderLabel.removeFromSuperview() + } + if let oldQueryViewController = self.queryViewController { + oldQueryViewController.view.removeFromSuperview() + oldQueryViewController.removeFromParent() + } + + let queryViewController = QueryViewController(mongoController: mongoController, collection: collection) + self.queryViewController = queryViewController + queryViewController.view.translatesAutoresizingMaskIntoConstraints = false + addChild(queryViewController) + detailContainerView.addSubview(queryViewController.view) + NSLayoutConstraint.activate([ + queryViewController.view.leadingAnchor.constraint(equalTo: detailContainerView.leadingAnchor), + queryViewController.view.trailingAnchor.constraint(equalTo: detailContainerView.trailingAnchor), + queryViewController.view.topAnchor.constraint(equalTo: detailContainerView.topAnchor), + queryViewController.view.bottomAnchor.constraint(equalTo: detailContainerView.bottomAnchor) + ]) + + self.title = queryViewController.title + } else { + if let queryViewController = queryViewController { + queryViewController.view.removeFromSuperview() + queryViewController.removeFromParent() + } + + if self.placeholderLabel == nil { + let label = NSTextField(labelWithString: "Select a collection to begin") + self.placeholderLabel = label + label.translatesAutoresizingMaskIntoConstraints = false + detailContainerView.addSubview(label) + NSLayoutConstraint.activate([ + label.centerXAnchor.constraint(equalTo: detailContainerView.centerXAnchor), + label.centerYAnchor.constraint(equalTo: detailContainerView.centerYAnchor) + ]) + + self.title = "No Query" + } + } + } + + @objc func cellDoubleClicked() { + let item = collectionsOutlineView.item(atRow: collectionsOutlineView.clickedRow)! + + if item is DatabaseCollections { + if collectionsOutlineView.isItemExpanded(item) { + collectionsOutlineView.collapseItem(item) + } else { + collectionsOutlineView.expandItem(item) + } + } else if let collection = item as? DatabaseCollection { + // only open a new window/tab if our own query has changed from the default, otherwise replace our query controller + if let queryViewController = queryViewController, queryViewController.hasQueryChanged { + (NSApplication.shared.delegate as! AppDelegate).newWindow(mongoController: mongoController, collection: collection) + } else { + self.selectedCollection = collection + updateDetailView() + } + } + } + + @IBAction func runQuery(_ sender: Any) { + guard let queryViewController = queryViewController else { + return + } + queryViewController.runQuery() + } +} + +extension DatabaseViewController: NSMenuItemValidation { + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + if menuItem.action == #selector(runQuery(_:)) { + return queryViewController != nil + } + return true + } +} + +extension DatabaseViewController: NSOutlineViewDataSource { + func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { + if item == nil { + return databaseCollections.count + } else if let database = item as? DatabaseCollections { + return database.collections.count + } else { + return 0 + } + } + + func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { + return item is DatabaseCollections + } + + func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { + if item == nil { + return databaseCollections[index] + } else if let databaseCollections = item as? DatabaseCollections { + let collection = databaseCollections.collections[index] + return DatabaseCollection(database: databaseCollections.database, name: collection) + } else { + fatalError() + } + } +} + +extension DatabaseViewController: NSOutlineViewDelegate { + func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { + if let database = item as? DatabaseCollections { + let cell = outlineView.makeView(withIdentifier: .databaseNameCell, owner: nil) as! NSTableCellView + cell.textField!.stringValue = database.database + cell.textField!.isEditable = false + return cell + } else if let collection = item as? DatabaseCollection { + let cell = outlineView.makeView(withIdentifier: .collectionNameCell, owner: nil) as! NSTableCellView + cell.textField!.stringValue = collection.name + cell.textField!.isEditable = false + return cell + } else { + fatalError() + } + } +} + +extension NSUserInterfaceItemIdentifier { + static let databaseNameCell = NSUserInterfaceItemIdentifier(rawValue: "DatabaseNameCell") + static let collectionNameCell = NSUserInterfaceItemIdentifier(rawValue: "CollectionNameCell") +} diff --git a/MongoView/View Controllers/DatabaseViewController.xib b/MongoView/View Controllers/DatabaseViewController.xib new file mode 100644 index 0000000..5526a6f --- /dev/null +++ b/MongoView/View Controllers/DatabaseViewController.xib @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/View Controllers/QueryViewController.swift b/MongoView/View Controllers/QueryViewController.swift new file mode 100644 index 0000000..d100ac8 --- /dev/null +++ b/MongoView/View Controllers/QueryViewController.swift @@ -0,0 +1,166 @@ +// +// QueryViewController.swift +// MongoView +// +// Created by Shadowfacts on 1/9/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa +import MongoSwift + +class QueryViewController: NSViewController { + + @IBOutlet weak var verticalSplitView: NSSplitView! + @IBOutlet var queryTextView: NSTextView! + @IBOutlet weak var outlineView: NSOutlineView! + @IBOutlet weak var documentCountLabel: NSTextField! + + let mongoController: MongoController + let collection: DatabaseCollection + + var defaultQuery: String { + "db.getCollection('\(collection.name)').find({})" + } + + var hasQueryChanged: Bool { + return queryTextView.string != defaultQuery + } + + var rootNodes: [Node] = [] + + init(mongoController: MongoController, collection: DatabaseCollection) { + self.mongoController = mongoController + self.collection = collection + + super.init(nibName: "QueryViewController", bundle: .main) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + let db = mongoController.client.db(collection.database) + let collection = db.collection(self.collection.name) + let documents = try! collection.find().all() + rootNodes = documents.map { Node(document: $0) } + + verticalSplitView.delegate = self + verticalSplitView.setHoldingPriority(.defaultHigh, forSubviewAt: 0) + + queryTextView.font = .monospacedSystemFont(ofSize: 13, weight: .regular) + queryTextView.isAutomaticQuoteSubstitutionEnabled = false + queryTextView.string = defaultQuery + + outlineView.dataSource = self + outlineView.delegate = self + + outlineView.target = self + outlineView.doubleAction = #selector(outlineCellDoubleClicked) + + title = "\(self.collection.database).\(self.collection.name)" + + documentCountLabel.stringValue = "\(documents.count) document\(documents.count == 1 ? "" : "s")" + } + + override func viewWillAppear() { + super.viewWillAppear() + + verticalSplitView.setPosition(80, ofDividerAt: 0) + + } + + override func viewDidAppear() { + super.viewDidAppear() + + + view.window!.makeFirstResponder(outlineView) + } + + func runQuery() { + print("run query: \(queryTextView.string)") +// mongoController.db.runCommand(["eval": .code(Code(code: queryTextView.string))]).whenComplete { (res) in +// print(res) +// } + } + + @objc func outlineCellDoubleClicked() { + if let item = outlineView.item(atRow: outlineView.clickedRow) { + if outlineView.isItemExpanded(item) { + outlineView.collapseItem(item) + } else { + outlineView.expandItem(item) + } + } + } + +} + +extension QueryViewController: NSSplitViewDelegate { + func splitView(_ splitView: NSSplitView, constrainSplitPosition proposedPosition: CGFloat, ofSubviewAt dividerIndex: Int) -> CGFloat { + return max(80, min(splitView.bounds.height / 2, proposedPosition)) + } +} + +extension QueryViewController: NSOutlineViewDataSource { + func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { + if item == nil { + return rootNodes.count + } else if let node = item as? Node { + return node.numberOfChildren + } else { + return 0 + } + } + + func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool { + if let node = item as? Node { + return node.hasChildren + } else { + return false + } + } + + func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { + if item == nil { + return rootNodes[index] + } else if let node = item as? Node { + return node.children[index] + } else { + fatalError("unreachable") + } + } +} + +extension QueryViewController: NSOutlineViewDelegate { + func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? { + guard let tableColumn = tableColumn, + let node = item as? Node else { + fatalError() + } + if tableColumn.identifier == .fieldNameColumn { + let cell = outlineView.makeView(withIdentifier: .fieldNameCell, owner: nil) as! NSTableCellView + cell.textField!.stringValue = node.keyString + cell.textField!.isEditable = false + return cell + } else if tableColumn.identifier == .fieldValueColumn { + let cell = outlineView.makeView(withIdentifier: .fieldValueCell, owner: nil) as! NSTableCellView + cell.textField!.stringValue = node.valueString + cell.textField!.isEditable = false + return cell + } else { + return nil + } + } +} + + +extension NSUserInterfaceItemIdentifier { + static let fieldNameColumn = NSUserInterfaceItemIdentifier(rawValue: "FieldNameCol") + static let fieldValueColumn = NSUserInterfaceItemIdentifier(rawValue: "FieldValueCol") + static let fieldNameCell = NSUserInterfaceItemIdentifier(rawValue: "FieldNameCell") + static let fieldValueCell = NSUserInterfaceItemIdentifier(rawValue: "FieldValueCell") +} diff --git a/MongoView/View Controllers/QueryViewController.xib b/MongoView/View Controllers/QueryViewController.xib new file mode 100644 index 0000000..a26f4ba --- /dev/null +++ b/MongoView/View Controllers/QueryViewController.xib @@ -0,0 +1,1108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + eu + hr_BA + en_CM + en_BI + en_AE + rw_RW + ast + en_SZ + he_IL + ar + uz_Arab + en_PN + as + en_NF + ks_IN + es_KY + rwk_TZ + zh_Hant_TW + en_CN + gsw_LI + ta_IN + th_TH + es_EA + fr_GF + nso + ar_001 + en_RW + tr_TR + de_CH + ee_TG + en_NG + byn + fr_TG + fr_SC + az + es_HN + en_CO + pa_Aran_PK + en_AG + ccp_IN + gsw + ru_KZ + ks_Aran + dyo + so_ET + ff_Latn + zh_Hant_MO + de_BE + km_KH + nus_SS + my_MM + mgh_MZ + ee_GH + es_EC + kw_GB + rm_CH + en_ME + nyn + mk_MK + bs_Cyrl_BA + ar_MR + es_GL + en_BM + ms_Arab + en_AI + gl_ES + en_PR + trv_TW + ne_IN + or_IN + byn_ER + khq_ML + ia_001 + en_MG + iu_CA + en_LC + pt_TL + ta_SG + tn_ZA + myv + syr + jmc_TZ + ceb_PH + om_ET + lv_LV + ps_PK + es_US + ceb + en_PT + vai_Latn_LR + en_NL + to_TO + cgg_UG + en_MH + ta + ur_Arab_PK + xh + zu_ZA + shi_Latn_MA + es_FK + ar_KM + en_AL + brx_IN + te + chr_US + yo_BJ + fr_VU + pa + ks_Arab + sat_Olck + kea + ksh_DE + sw_CD + te_IN + fr_RE + tg + th + ur_IN + ti + yo_NG + es_HT + es_GP + nqo_GN + guz_KE + tk + kl_GL + ksf_CM + mua_CM + lag_TZ + lb + fr_TN + tn + es_PA + pl_PL + to + hi_IN + dje_NE + es_GQ + en_BR + kok_IN + ss_ZA + fr_GN + pl + bem + ha + ckb + es_CA + lg + tr + en_PW + ts + tt + en_NO + nyn_UG + nr_ZA + oc_FR + sr_Latn_RS + jbo + gsw_FR + he + pa_Guru + ps_AF + lu_CD + mgo_CM + qu_BO + en_BS + sn_ZW + da + ps + ss_SZ + ln + pt + hi + lo + ebu + de + gu_IN + wo_SN + seh + en_CX + en_ZM + mni_Mtei + fr_HT + fr_GP + pt_GQ + lt + lu + es_TT + ln_CD + vai_Latn + el_GR + lv + en_MM + io_001 + en_KE + sbp + ff_Latn_GW + hr + ur_Aran_PK + en_CY + es_GT + twq_NE + zh_Hant_HK + kln_KE + fr_GQ + chr + hu + es_UY + fr_CA + ms_BN + en_NR + mer + fr_SN + es_PE + shi + bez + sw_TZ + wae_CH + kkj + hy + dz_BT + en_CZ + teo_KE + teo + en_AR + ar_JO + yue_Hans_CN + mer_KE + dv + khq + ln_CF + nn_NO + es_SR + en_MO + ve_ZA + gez + ar_TD + dz + ses + en_BW + en_AS + ar_IL + es_BB + bo_CN + nnh + mni + ff_Latn_GM + hy_AM + ln_CG + sr_Latn_BA + teo_UG + en_MP + ksb_TZ + ar_SA + smn_FI + ar_LY + en_AT + so_KE + fr_CD + af_NA + en_NU + es_PH + en_KI + ba_RU + en_JE + ff_Latn_GH + lkt + dv_MV + en_AU + fa_IR + pt_FR + uz_Latn_UZ + zh_Hans_CN + ewo_CM + jv_ID + fr_PF + ca_IT + es_GY + en_BZ + ar_KW + am_ET + fr_FR + ff_Latn_SL + en_VC + es_DM + fr_DJ + pt_GW + fr_CF + es_SV + en_MS + nqo + pt_ST + ar_SD + luy_KE + gd_GB + de_LI + it_VA + fr_CG + pt_CH + ckb_IQ + zh_Hans_SG + en_MT + sc_IT + ha_NE + en_ID + ewo + af_ZA + om_KE + os_GE + wa + nl_SR + es_ES + es_DO + ar_IQ + sat_Olck_IN + en_UA + tig_ER + fr_CH + nnh_CM + es_SX + es_419 + en_MU + en_US_POSIX + yav_CM + luo_KE + dua_CM + et_EE + en_IE + ak_GH + sa + rwk + sc + es_CL + kea_CV + sd + fr_CI + ckb_IR + fr_BE + se + en_NZ + syr_IQ + en_MV + en_LR + es_PM + en_KN + nb_SJ + ha_NG + sg + tn_BW + sr_Cyrl_RS + ru_RU + en_ZW + oc + ga_IE + si + sv_AX + wo + en_VG + ky_KG + agq_CM + mzn + fr_BF + naq_NA + mr_IN + en_MW + de_AT + az_Latn + en_LS + ka + sk + sl + sat_Deva_IN + sn + sr_Latn_ME + wa_BE + fr_NC + so + is_IS + kpe_LR + twq + ig_NG + sq + fo_FO + sd_Deva + sr + ga + eo_001 + en_MX + om + en_LT + bas_CM + se_NO + ss + st + tzm + ki + nl_BE + ar_QA + gd + sv + kk + pa_Aran + rn_BI + es_CO + az_Latn_AZ + kl + en_VI + es_AG + ca + or + km + os + sw + en_MY + kn + en_LU + fr_SY + ar_TN + en_JM + fr_PM + ko + st_ZA + fr_NE + ce + fr_MA + co_FR + nso_ZA + gl + ru_MD + kaj_NG + es_BL + ks + fr_CM + lb_LU + gv_IM + fr_BI + gn + saq_KE + en_LV + ku + en_KR + ks_Arab_IN + es_NI + en_GB + kw + nl_SX + dav_KE + tr_CY + ky + en_UG + es_BM + en_TC + es_AI + ar_EG + fr_BJ + co + gu + es_PR + fr_RW + gv + lrc_IQ + kcg + sr_Cyrl_BA + es_MF + fr_MC + cs + bez_TZ + es_CR + asa_TZ + ar_EH + fo_DK + ms_Arab_BN + cv + ccp + en_JP + sbp_TZ + en_IL + lt_LT + mfe + en_GD + moh_CA + cy + es_LC + ca_FR + ts_ZA + ff_Latn_SN + ug_CN + es_BO + en_SA + fr_BL + bn_IN + uz_Cyrl_UZ + lrc_IR + az_Cyrl + en_IM + sw_KE + en_SB + pa_Arab + ur_PK + haw_US + ar_SO + en_IN + cv_RU + fil + fr_MF + scn + en_WS + es_CU + es_BQ + ja_JP + fy_NL + en_SC + yue_Hant_HK + en_IO + pt_PT + en_HK + ks_Aran_IN + en_GG + fr_MG + ff_Latn_MR + de_LU + tig + zh_Hant_CN + tzm_MA + es_BR + en_TH + en_SD + nds_DE + ln_AO + ny_MW + shi_Tfng + as_IN + en_GH + ms_MY + ro_RO + jgo_CM + es_CW + dua + en_UM + es_BS + en_SE + kn_IN + en_KY + vun_TZ + kln + lrc + en_GI + moh + ca_ES + mni_Mtei_IN + rof + pt_CV + kok + pt_BR + ar_DJ + yi_001 + fi_FI + zh + es_PY + ar_SS + arn + ve + mua + sr_Cyrl_ME + hi_Latn + vai_Vaii_LR + en_001 + nl_NL + en_TK + ca_AD + en_SG + fr_DZ + si_LK + sv_SE + pt_AO + mni_Beng + vi + xog_UG + xog + en_IS + syr_SY + nb + seh_MZ + es_AR + sk_SK + en_SH + ti_ER + nd + az_Cyrl_AZ + zu + ne + nd_ZW + kcg_NG + el_CY + en_IT + nl_BQ + da_GL + ja + wal_ET + rm + fr_ML + gaa_GH + rn + en_VU + ff_Latn_BF + ro + ebu_KE + rof_TZ + ru_KG + en_SI + sa_IN + sg_CF + mfe_MU + nl + brx + bs_Latn + fa + zgh_MA + ff_Latn_LR + en_GM + shi_Latn + en_FI + nn + en_EE + ru + yue + kam_KE + fur + vai_Vaii + ar_ER + rw + ti_ET + ff + luo + nr + ur_Arab_IN + ba + fa_AF + nl_CW + es_MQ + en_HR + en_FJ + fi + pt_MO + be + en_US + en_TO + en_SK + bg + mi_NZ + arn_CL + ny + ru_BY + it_IT + ml_IN + gsw_CH + qu_EC + fo + ff_Latn_CM + sv_FI + en_FK + nus + ff_Latn_NE + jv + ta_LK + vun + sr_Latn + es_BZ + fr + en_SL + bm + es_VC + trv + ar_BH + guz + bn + bo + ar_SY + es_MS + lo_LA + ne_NP + uz_Latn + be_BY + es_IC + sr_Latn_XK + ar_MA + pa_Guru_IN + br + luy + kde_TZ + es_AW + bs + fy + fur_IT + gez_ER + hu_HU + ar_AE + gaa + en_HU + sah_RU + zh_Hans + en_FM + fr_MQ + ko_KP + en_150 + en_DE + ce_RU + en_CA + hsb_DE + sq_AL + wuu + en_TR + ro_MD + es_VE + tg_TJ + fr_WF + mt_MT + kab + nmg_CM + ms_SG + en_GR + ru_UA + fr_MR + xh_ZA + zh_Hans_MO + de_IT + ku_TR + ccp_BD + kpe_GN + ur_Aran_IN + myv_RU + bs_Cyrl + nds_NL + es_KN + sw_UG + tt_RU + ko_KR + yue_Hans + en_DG + bo_IN + en_CC + shi_Tfng_MA + lag + it_SM + en_TT + ms_Arab_MY + os_RU + sq_MK + es_VG + kaj + bem_ZM + kde + ur_Aran + ar_OM + kk_KZ + cgg + gez_ET + bas + kam + scn_IT + es_MX + sah + wae + en_GU + zh_Hant + fr_MU + fr_KM + ar_LB + en_BA + sat_Deva + en_TV + sr_Cyrl + mzn_IR + es_VI + dje + kab_DZ + fil_PH + se_SE + vai + hr_HR + bs_Latn_BA + nl_AW + dav + so_SO + ar_PS + en_FR + uz_Cyrl + jbo_001 + en_BB + ki_KE + en_TW + naq + en_SS + mg_MG + mas_KE + ff_Latn_GN + en_RO + en_PG + mgh + dyo_SN + wal + mas + agq + bn_BD + haw + yi + nb_NO + da_DK + en_DK + saq + st_LS + ug + cy_GB + fr_YT + jmc + ses_ML + en_PH + de_DE + ar_YE + es_TC + bm_ML + yo + lkt_US + uz_Arab_AF + jgo + sl_SI + gn_PY + pt_LU + sat + en_CH + asa + en_BD + uk + lg_UG + nds + qu_PE + mgo + id_ID + en_NA + en_GY + ff_Latn_NG + zgh + dsb + fr_LU + pt_MZ + mas_TZ + en_DM + ia + es_GD + en_BE + mg + sd_PK + ta_MY + fr_GA + ka_GE + nmg + en_TZ + ur + eu_ES + ar_DZ + mi + ur_Arab + id + so_DJ + kpe + hsb + yav + mk + ml + pa_Arab_PK + en_ER + ig + se_FI + mn + ksb + uz + vi_VN + ii + qu + en_RS + en_PK + ee + ast_ES + yue_Hant + mr + ms + en_ES + ha_GH + it_CH + sq_XK + mt + en_CK + br_FR + en_BG + io + es_GF + sr_Cyrl_XK + ksf + en_SX + bg_BG + tk_TM + en_PL + af + el + cs_CZ + fr_TD + ks_Deva + zh_Hans_HK + is + ksh + my + mn_MN + en + it + dsb_DE + ii_CN + eo + iu + en_CL + en_ZA + en_AD + smn + mni_Beng_IN + ak + en_RU + kkj_CM + am + es + et + uk_UA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/View Controllers/ServerConnectViewController.swift b/MongoView/View Controllers/ServerConnectViewController.swift new file mode 100644 index 0000000..9a1574d --- /dev/null +++ b/MongoView/View Controllers/ServerConnectViewController.swift @@ -0,0 +1,89 @@ +// +// ServerConnectViewController.swift +// MongoView +// +// Created by Shadowfacts on 1/11/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa + +protocol ServerConnectViewControllerDelegate: class { + func connectToServer(mongoController: MongoController) +} + +class ServerConnectViewController: NSViewController { + + weak var delegate: ServerConnectViewControllerDelegate? + + @IBOutlet weak var hostTextField: NSTextField! + @IBOutlet weak var portTextField: NSTextField! + @IBOutlet weak var usernameTextField: NSTextField! + @IBOutlet weak var passwordTextField: NSSecureTextField! + @IBOutlet weak var connectButton: NSButton! + + init() { + super.init(nibName: "ServerConnectViewController", bundle: .main) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + hostTextField.delegate = self + portTextField.delegate = self + + hostTextField.nextKeyView = portTextField + portTextField.nextKeyView = usernameTextField + usernameTextField.nextKeyView = passwordTextField + passwordTextField.nextKeyView = hostTextField + + updateConnectButtonEnabled() + } + + override func viewWillAppear() { + super.viewWillAppear() + + view.window!.initialFirstResponder = hostTextField + } + + func updateConnectButtonEnabled() { + connectButton.isEnabled = !hostTextField.stringValue.isEmpty && !portTextField.stringValue.isEmpty + } + + @IBAction func connect(_ sender: Any) { + connectButton.isEnabled = false + hostTextField.isEnabled = false + portTextField.isEnabled = false + usernameTextField.isEnabled = false + passwordTextField.isEnabled = false + + var str = "mongodb://" + if !usernameTextField.stringValue.isEmpty { + str += usernameTextField.stringValue + if !passwordTextField.stringValue.isEmpty { + str.append(":") + str.append(passwordTextField.stringValue) + } + str.append("@") + } + str.append(hostTextField.stringValue) + str.append(":") + str.append(portTextField.stringValue) + + let mongoController = MongoController(connectionString: str) + mongoController.setup() + + delegate?.connectToServer(mongoController: mongoController) + } + +} + +extension ServerConnectViewController: NSTextFieldDelegate { + func controlTextDidChange(_ obj: Notification) { + updateConnectButtonEnabled() + } +} diff --git a/MongoView/View Controllers/ServerConnectViewController.xib b/MongoView/View Controllers/ServerConnectViewController.xib new file mode 100644 index 0000000..04f24ae --- /dev/null +++ b/MongoView/View Controllers/ServerConnectViewController.xib @@ -0,0 +1,212 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + NSAllRomanInputSourcesLocaleIdentifier + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/Windows/DatabaseWindowController.swift b/MongoView/Windows/DatabaseWindowController.swift new file mode 100644 index 0000000..8a7a5bb --- /dev/null +++ b/MongoView/Windows/DatabaseWindowController.swift @@ -0,0 +1,56 @@ +// +// DatabaseWindowController.swift +// MongoView +// +// Created by Shadowfacts on 1/9/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa + +class DatabaseWindowController: NSWindowController { + + private var titleObservation: NSKeyValueObservation? + + var mongoController: MongoController! + var initialCollection: DatabaseCollection? + + private var databaseViewController: DatabaseViewController! + + convenience init() { + self.init(windowNibName: "DatabaseWindowController") + } + + override func windowDidLoad() { + super.windowDidLoad() + + if mongoController == nil { + mongoController = MongoController(connectionString: "mongodb://localhost:27017") + mongoController.setup() + } + + databaseViewController = DatabaseViewController(mongoController: mongoController) + contentViewController = databaseViewController + + if let initialCollection = initialCollection { + databaseViewController.showCollection(initialCollection) + } + + titleObservation = observe(\.contentViewController?.title) { [unowned self] (_, _) in + self.updateWindowTitle() + } + updateWindowTitle() + + window!.tabbingMode = .preferred + window!.tabbingIdentifier = mongoController.connectionString + } + + override func newWindowForTab(_ sender: Any?) { + (NSApplication.shared.delegate as! AppDelegate).newWindow(mongoController: mongoController) + } + + private func updateWindowTitle() { + window?.title = databaseViewController.title ?? "MongoView" + } + +} diff --git a/MongoView/Windows/DatabaseWindowController.xib b/MongoView/Windows/DatabaseWindowController.xib new file mode 100644 index 0000000..3a204bf --- /dev/null +++ b/MongoView/Windows/DatabaseWindowController.xib @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/Windows/ServerConnectWindowController.swift b/MongoView/Windows/ServerConnectWindowController.swift new file mode 100644 index 0000000..5b4ec0c --- /dev/null +++ b/MongoView/Windows/ServerConnectWindowController.swift @@ -0,0 +1,27 @@ +// +// ServerConnectWindowController.swift +// MongoView +// +// Created by Shadowfacts on 1/11/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa + +class ServerConnectWindowController: NSWindowController { + + weak var delegate: ServerConnectViewControllerDelegate? + + convenience init() { + self.init(windowNibName: "ServerConnectWindowController") + } + + override func windowDidLoad() { + super.windowDidLoad() + + let vc = ServerConnectViewController() + vc.delegate = delegate + contentViewController = vc + } + +} diff --git a/MongoView/Windows/ServerConnectWindowController.xib b/MongoView/Windows/ServerConnectWindowController.xib new file mode 100644 index 0000000..e23b4dd --- /dev/null +++ b/MongoView/Windows/ServerConnectWindowController.xib @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +