From 54f8236332e066bf0902aae3123582fc7171acfd Mon Sep 17 00:00:00 2001 From: Shadowfacts Date: Wed, 12 Aug 2020 10:53:40 -0400 Subject: [PATCH] Split DatabaseViewController into multiple VCs --- MongoView.xcodeproj/project.pbxproj | 32 ++- MongoView/DatabaseCollection.swift | 23 ++ ...DatabaseCollectionListViewController.swift | 127 ++++++++++ .../DatabaseCollectionListViewController.xib | 108 +++++++++ .../DatabaseViewController.swift | 218 ------------------ .../DatabaseViewController.xib | 143 ------------ .../DetailViewController.swift | 17 ++ .../View Controllers/DetailViewController.xib | 35 +++ .../MainSplitViewController.swift | 105 +++++++++ .../QueryViewController.swift | 7 - .../Windows/DatabaseWindowController.swift | 16 +- 11 files changed, 445 insertions(+), 386 deletions(-) create mode 100644 MongoView/DatabaseCollection.swift create mode 100644 MongoView/View Controllers/DatabaseCollectionListViewController.swift create mode 100644 MongoView/View Controllers/DatabaseCollectionListViewController.xib delete mode 100644 MongoView/View Controllers/DatabaseViewController.swift delete mode 100644 MongoView/View Controllers/DatabaseViewController.xib create mode 100644 MongoView/View Controllers/DetailViewController.swift create mode 100644 MongoView/View Controllers/DetailViewController.xib create mode 100644 MongoView/View Controllers/MainSplitViewController.swift diff --git a/MongoView.xcodeproj/project.pbxproj b/MongoView.xcodeproj/project.pbxproj index 48ec848..7e2d822 100644 --- a/MongoView.xcodeproj/project.pbxproj +++ b/MongoView.xcodeproj/project.pbxproj @@ -17,6 +17,12 @@ D626BF83243BD2EE0075117B /* EditDocumentWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D626BF81243BD2EE0075117B /* EditDocumentWindowController.xib */; }; D626BF86243BE19A0075117B /* EditDocumentViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D626BF84243BE19A0075117B /* EditDocumentViewController.swift */; }; D626BF87243BE19A0075117B /* EditDocumentViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D626BF85243BE19A0075117B /* EditDocumentViewController.xib */; }; + D627CE7E24E38F3B00C39FE5 /* MainSplitViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627CE7C24E38F3A00C39FE5 /* MainSplitViewController.swift */; }; + D627CE8224E38FBE00C39FE5 /* DatabaseCollectionListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627CE8024E38FBE00C39FE5 /* DatabaseCollectionListViewController.swift */; }; + D627CE8324E38FBE00C39FE5 /* DatabaseCollectionListViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627CE8124E38FBE00C39FE5 /* DatabaseCollectionListViewController.xib */; }; + D627CE8824E399F100C39FE5 /* DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627CE8624E399F100C39FE5 /* DetailViewController.swift */; }; + D627CE8924E399F100C39FE5 /* DetailViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = D627CE8724E399F100C39FE5 /* DetailViewController.xib */; }; + D627CE8B24E438EE00C39FE5 /* DatabaseCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D627CE8A24E438EE00C39FE5 /* DatabaseCollection.swift */; }; 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 */; }; @@ -44,8 +50,6 @@ 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 */; }; D6A7D096243541A400B46857 /* WindowStatusView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A7D095243541A400B46857 /* WindowStatusView.swift */; }; D6A7D09A243546B500B46857 /* WindowStatusView.xib in Resources */ = {isa = PBXBuildFile; fileRef = D6A7D099243546B500B46857 /* WindowStatusView.xib */; }; D6A7D0A42435885B00B46857 /* JavaScriptHighlighter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6A7D0A32435885B00B46857 /* JavaScriptHighlighter.swift */; }; @@ -97,6 +101,12 @@ D626BF81243BD2EE0075117B /* EditDocumentWindowController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EditDocumentWindowController.xib; sourceTree = ""; }; D626BF84243BE19A0075117B /* EditDocumentViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditDocumentViewController.swift; sourceTree = ""; }; D626BF85243BE19A0075117B /* EditDocumentViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = EditDocumentViewController.xib; sourceTree = ""; }; + D627CE7C24E38F3A00C39FE5 /* MainSplitViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainSplitViewController.swift; sourceTree = ""; }; + D627CE8024E38FBE00C39FE5 /* DatabaseCollectionListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseCollectionListViewController.swift; sourceTree = ""; }; + D627CE8124E38FBE00C39FE5 /* DatabaseCollectionListViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DatabaseCollectionListViewController.xib; sourceTree = ""; }; + D627CE8624E399F100C39FE5 /* DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailViewController.swift; sourceTree = ""; }; + D627CE8724E399F100C39FE5 /* DetailViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = DetailViewController.xib; sourceTree = ""; }; + D627CE8A24E438EE00C39FE5 /* DatabaseCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatabaseCollection.swift; 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 = ""; }; @@ -118,8 +128,6 @@ 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 = ""; }; D6A7D095243541A400B46857 /* WindowStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowStatusView.swift; sourceTree = ""; }; D6A7D099243546B500B46857 /* WindowStatusView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = WindowStatusView.xib; sourceTree = ""; }; D6A7D0A32435885B00B46857 /* JavaScriptHighlighter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JavaScriptHighlighter.swift; sourceTree = ""; }; @@ -174,8 +182,11 @@ children = ( D60C863D23CA2E2100C9DB8E /* ServerConnectViewController.swift */, D60C863E23CA2E2100C9DB8E /* ServerConnectViewController.xib */, - D63CDF4223C970C50012D658 /* DatabaseViewController.swift */, - D63CDF4323C970C50012D658 /* DatabaseViewController.xib */, + D627CE7C24E38F3A00C39FE5 /* MainSplitViewController.swift */, + D627CE8024E38FBE00C39FE5 /* DatabaseCollectionListViewController.swift */, + D627CE8124E38FBE00C39FE5 /* DatabaseCollectionListViewController.xib */, + D627CE8624E399F100C39FE5 /* DetailViewController.swift */, + D627CE8724E399F100C39FE5 /* DetailViewController.xib */, D63CDF3E23C839010012D658 /* QueryViewController.swift */, D63CDF3F23C839010012D658 /* QueryViewController.xib */, D626BF84243BE19A0075117B /* EditDocumentViewController.swift */, @@ -220,6 +231,7 @@ D63CDF3423C838190012D658 /* MongoController.swift */, D6ABB01324B4DE7600F79DA8 /* StatusManager.swift */, D63CDF3323C838190012D658 /* Node.swift */, + D627CE8A24E438EE00C39FE5 /* DatabaseCollection.swift */, D6D4665223CB730C00F13B1B /* MongoEvaluator.swift */, D624090E243903E90020E09F /* ExtendedJSON.swift */, D6A7D0A22435880700B46857 /* Synax Highlighting */, @@ -350,9 +362,10 @@ D63CDEC023C837DD0012D658 /* Assets.xcassets in Resources */, D60C863A23CA2DD100C9DB8E /* ServerConnectWindowController.xib in Resources */, D626BF87243BE19A0075117B /* EditDocumentViewController.xib in Resources */, - D63CDF4523C970C50012D658 /* DatabaseViewController.xib in Resources */, D6A7D09A243546B500B46857 /* WindowStatusView.xib in Resources */, D63CDF3D23C838470012D658 /* DatabaseWindowController.xib in Resources */, + D627CE8924E399F100C39FE5 /* DetailViewController.xib in Resources */, + D627CE8324E38FBE00C39FE5 /* DatabaseCollectionListViewController.xib in Resources */, D63CDEC323C837DD0012D658 /* MainMenu.xib in Resources */, D626BF83243BD2EE0075117B /* EditDocumentWindowController.xib in Resources */, D63CDF4123C839010012D658 /* QueryViewController.xib in Resources */, @@ -366,6 +379,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + D627CE8B24E438EE00C39FE5 /* DatabaseCollection.swift in Sources */, D63CDEBE23C837DC0012D658 /* AppDelegate.swift in Sources */, D6D4665323CB730C00F13B1B /* MongoEvaluator.swift in Sources */, D624090F243903E90020E09F /* ExtendedJSON.swift in Sources */, @@ -373,13 +387,15 @@ D60C863923CA2DD100C9DB8E /* ServerConnectWindowController.swift in Sources */, D63CDF3723C8381A0012D658 /* Node.swift in Sources */, D626BF86243BE19A0075117B /* EditDocumentViewController.swift in Sources */, + D627CE8224E38FBE00C39FE5 /* DatabaseCollectionListViewController.swift in Sources */, D60C863F23CA2E2100C9DB8E /* ServerConnectViewController.swift in Sources */, - D63CDF4423C970C50012D658 /* DatabaseViewController.swift in Sources */, + D627CE8824E399F100C39FE5 /* DetailViewController.swift in Sources */, D63CDF3C23C838470012D658 /* DatabaseWindowController.swift in Sources */, D6A7D096243541A400B46857 /* WindowStatusView.swift in Sources */, D626BF82243BD2EE0075117B /* EditDocumentWindowController.swift in Sources */, D6A7D0A42435885B00B46857 /* JavaScriptHighlighter.swift in Sources */, D6ABB01424B4DE7600F79DA8 /* StatusManager.swift in Sources */, + D627CE7E24E38F3B00C39FE5 /* MainSplitViewController.swift in Sources */, D62408C12438CF550020E09F /* JavaScriptEditorView.swift in Sources */, D63CDF4023C839010012D658 /* QueryViewController.swift in Sources */, ); diff --git a/MongoView/DatabaseCollection.swift b/MongoView/DatabaseCollection.swift new file mode 100644 index 0000000..99e9244 --- /dev/null +++ b/MongoView/DatabaseCollection.swift @@ -0,0 +1,23 @@ +// +// DatabaseCollection.swift +// MongoView +// +// Created by Shadowfacts on 8/12/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Foundation + +struct DatabaseCollections { + let database: String + let collections: [String] +} + +struct DatabaseCollection: CustomStringConvertible { + let database: String + let name: String + + var description: String { + return "\(database).\(name)" + } +} diff --git a/MongoView/View Controllers/DatabaseCollectionListViewController.swift b/MongoView/View Controllers/DatabaseCollectionListViewController.swift new file mode 100644 index 0000000..2d8db62 --- /dev/null +++ b/MongoView/View Controllers/DatabaseCollectionListViewController.swift @@ -0,0 +1,127 @@ +// +// DatabaseCollectionListViewController.swift +// MongoView +// +// Created by Shadowfacts on 8/11/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa +import NIO +import Combine + +class DatabaseCollectionListViewController: NSViewController { + + @IBOutlet weak var outlineView: NSOutlineView! + + let mongoController: MongoController + + let selectedCollection = PassthroughSubject() + + private var databaseCollections: [DatabaseCollections] = [] + + init(mongoController: MongoController) { + self.mongoController = mongoController + + super.init(nibName: "DatabaseCollectionListViewController", 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: String) -> EventLoopFuture in + let db = self.mongoController.client.db(name) + return db.listCollectionNames().map { (collectionNames: [String]) -> DatabaseCollections in + let sortedNames = collectionNames.sorted() + return DatabaseCollections(database: name, collections: sortedNames) + } + } + 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): + let sortedCollections = databaseCollections.sorted(by: { $0.database < $1.database }) + self.databaseCollections = sortedCollections + DispatchQueue.main.async { + self.outlineView.reloadData() + } + case let .failure(error): + fatalError("error getting database names: \(error)") + } + } + + outlineView.dataSource = self + outlineView.delegate = self + } + + @IBAction func outlineCellDoubleClicked(_ sender: Any) { + let item = outlineView.item(atRow: outlineView.clickedRow)! + + if item is DatabaseCollections { + if outlineView.isItemExpanded(item) { + outlineView.collapseItem(item) + } else { + outlineView.expandItem(item) + } + } else if let collection = item as? DatabaseCollection { + selectedCollection.send(collection) + } + } +} + +extension DatabaseCollectionListViewController: 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 DatabaseCollectionListViewController: 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/DatabaseCollectionListViewController.xib b/MongoView/View Controllers/DatabaseCollectionListViewController.xib new file mode 100644 index 0000000..ccca079 --- /dev/null +++ b/MongoView/View Controllers/DatabaseCollectionListViewController.xib @@ -0,0 +1,108 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/View Controllers/DatabaseViewController.swift b/MongoView/View Controllers/DatabaseViewController.swift deleted file mode 100644 index 5bbfce0..0000000 --- a/MongoView/View Controllers/DatabaseViewController.swift +++ /dev/null @@ -1,218 +0,0 @@ -// -// 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: CustomStringConvertible { - let database: String - let name: String - - var description: String { - return "\(database).\(name)" - } -} - -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: String) -> EventLoopFuture in - let db = self.mongoController.client.db(name) - return db.listCollectionNames().map { (collectionNames: [String]) -> DatabaseCollections in - let sortedNames = collectionNames.sorted() - return DatabaseCollections(database: name, collections: sortedNames) - } - } - 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): - let sortedCollections = databaseCollections.sorted(by: { $0.database < $1.database }) - self.databaseCollections = sortedCollections - 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.hasFilterChanged { - (NSApplication.shared.delegate as! AppDelegate).newWindow(mongoController: mongoController, collection: collection) - } else { - self.selectedCollection = collection - updateDetailView() - } - } - } - - @IBAction func refresh(_ sender: Any) { - queryViewController?.refresh() - } -} - -extension DatabaseViewController: NSMenuItemValidation { - func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { - if menuItem.action == #selector(refresh(_:)) { - 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 deleted file mode 100644 index 5526a6f..0000000 --- a/MongoView/View Controllers/DatabaseViewController.xib +++ /dev/null @@ -1,143 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MongoView/View Controllers/DetailViewController.swift b/MongoView/View Controllers/DetailViewController.swift new file mode 100644 index 0000000..e6b8247 --- /dev/null +++ b/MongoView/View Controllers/DetailViewController.swift @@ -0,0 +1,17 @@ +// +// DetailViewController.swift +// MongoView +// +// Created by Shadowfacts on 8/11/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa + +class DetailViewController: NSViewController { + + override func viewDidLoad() { + super.viewDidLoad() + } + +} diff --git a/MongoView/View Controllers/DetailViewController.xib b/MongoView/View Controllers/DetailViewController.xib new file mode 100644 index 0000000..d848fed --- /dev/null +++ b/MongoView/View Controllers/DetailViewController.xib @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/MongoView/View Controllers/MainSplitViewController.swift b/MongoView/View Controllers/MainSplitViewController.swift new file mode 100644 index 0000000..efed34e --- /dev/null +++ b/MongoView/View Controllers/MainSplitViewController.swift @@ -0,0 +1,105 @@ +// +// MainSplitViewController.swift +// MongoView +// +// Created by Shadowfacts on 8/11/20. +// Copyright © 2020 Shadowfacts. All rights reserved. +// + +import Cocoa +import Combine + +class MainSplitViewController: NSSplitViewController { + + let mongoController: MongoController + let initialCollection: DatabaseCollection? + + private var detailViewController = DetailViewController() + private var currentQueryViewController: QueryViewController? { + detailViewController.children.first as? QueryViewController + } + + private var collectionSubscriber: Cancellable? + private var titleObservation: NSKeyValueObservation? + + init(mongoController: MongoController, initialCollection: DatabaseCollection?) { + self.mongoController = mongoController + self.initialCollection = initialCollection + + super.init(nibName: nil, bundle: nil) + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + + let listVC = DatabaseCollectionListViewController(mongoController: mongoController) + let sourceListItem = NSSplitViewItem(sidebarWithViewController: listVC) + let detailItem = NSSplitViewItem(viewController: detailViewController) + detailItem.maximumThickness = NSSplitViewItem.unspecifiedDimension + + addSplitViewItem(sourceListItem) + addSplitViewItem(detailItem) + + NSLayoutConstraint.activate([ + sourceListItem.viewController.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 200), + sourceListItem.viewController.view.widthAnchor.constraint(lessThanOrEqualToConstant: 500), + detailItem.viewController.view.widthAnchor.constraint(greaterThanOrEqualToConstant: 200), + ]) + + collectionSubscriber = listVC.selectedCollection.sink(receiveValue: self.selectCollection) + + if let initialCollection = initialCollection { + selectCollection(initialCollection) + } + } + + private func selectCollection(_ collection: DatabaseCollection) { + if currentQueryViewController?.hasFilterChanged ?? false { + (NSApp.delegate as! AppDelegate).newWindow(mongoController: mongoController, collection: collection) + } else { + let queryVC = QueryViewController(mongoController: mongoController, collection: collection) + setDetailChild(queryVC) + } + } + + private func setDetailChild(_ vc: NSViewController) { + if let child = detailViewController.children.first { + child.removeFromParent() + child.view.removeFromSuperview() + } + + vc.view.translatesAutoresizingMaskIntoConstraints = false + + detailViewController.addChild(vc) + detailViewController.view.addSubview(vc.view) + + NSLayoutConstraint.activate([ + detailViewController.view.leadingAnchor.constraint(equalTo: vc.view.leadingAnchor), + detailViewController.view.trailingAnchor.constraint(equalTo: vc.view.trailingAnchor), + detailViewController.view.topAnchor.constraint(equalTo: vc.view.topAnchor), + detailViewController.view.bottomAnchor.constraint(equalTo: vc.view.bottomAnchor), + ]) + + titleObservation = vc.observe(\.title, options: .initial, changeHandler: { [unowned self] (_, _) in + self.title = vc.title + }) + } + + @IBAction func refresh(_ sender: Any) { + currentQueryViewController?.refresh() + } + +} + +extension MainSplitViewController: NSMenuItemValidation { + func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { + if menuItem.action == #selector(refresh(_:)) { + return currentQueryViewController != nil + } + return true + } +} diff --git a/MongoView/View Controllers/QueryViewController.swift b/MongoView/View Controllers/QueryViewController.swift index aff3821..44d4f96 100644 --- a/MongoView/View Controllers/QueryViewController.swift +++ b/MongoView/View Controllers/QueryViewController.swift @@ -67,13 +67,6 @@ class QueryViewController: NSViewController { verticalSplitView.setPosition(80, ofDividerAt: 0) } - - override func viewDidAppear() { - super.viewDidAppear() - - - view.window!.makeFirstResponder(outlineView) - } func refresh(reload: Bool = true) { let filterText = filterTextView.string.trimmingCharacters(in: .whitespacesAndNewlines) diff --git a/MongoView/Windows/DatabaseWindowController.swift b/MongoView/Windows/DatabaseWindowController.swift index 8fde203..5b895fd 100644 --- a/MongoView/Windows/DatabaseWindowController.swift +++ b/MongoView/Windows/DatabaseWindowController.swift @@ -20,7 +20,7 @@ class DatabaseWindowController: NSWindowController { var mongoController: MongoController! var initialCollection: DatabaseCollection? - private var databaseViewController: DatabaseViewController! + private var mainViewController: NSViewController! private var statusChangeHandler: Cancellable? private var connectionStatusChangeHandler: Cancellable? @@ -69,7 +69,7 @@ class DatabaseWindowController: NSWindowController { } private func updateWindowTitle() { - window?.title = databaseViewController?.title ?? "MongoView" + window?.title = mainViewController?.title ?? "MongoView" } private func updateStatusText(manager: StatusManager) { @@ -92,14 +92,10 @@ class DatabaseWindowController: NSWindowController { } private func initializeUI() { - databaseViewController = DatabaseViewController(mongoController: mongoController) + mainViewController = MainSplitViewController(mongoController: mongoController, initialCollection: initialCollection) // otherwise the VC size uses the size from the nib, potentially changing the window size - databaseViewController.view.frame = CGRect(origin: .zero, size: window!.frame.size) - contentViewController = databaseViewController - - if let initialCollection = initialCollection { - databaseViewController.showCollection(initialCollection) - } + mainViewController.view.frame = CGRect(origin: .zero, size: window!.frame.size) + contentViewController = mainViewController } } @@ -153,7 +149,7 @@ extension DatabaseWindowController: NSToolbarDelegate { item.label = "Refresh" item.paletteLabel = "Refresh" item.target = self - let button = NSButton(image: NSImage(named: NSImage.refreshTemplateName)!, target: nil, action: #selector(DatabaseViewController.refresh(_:))) + let button = NSButton(image: NSImage(named: NSImage.refreshTemplateName)!, target: nil, action: #selector(MainSplitViewController.refresh(_:))) button.bezelStyle = .texturedRounded item.view = button return item