From 73f035c5b70f438d5d73875a0614e40a5cc7bbc8 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Wed, 1 May 2019 16:04:56 -0500 Subject: [PATCH] Make OPML import and export respect multiple accounts --- Mac/AppDelegate.swift | 58 +++------- Mac/MainWindow/OPML/ExportOPMLSheet.xib | 101 ++++++++++++++++++ .../OPML/ExportOPMLWindowController.swift | 85 +++++++++++++++ Mac/MainWindow/OPML/ImportOPMLSheet.xib | 101 ++++++++++++++++++ .../OPML/ImportOPMLWindowController.swift | 82 ++++++++++++++ NetNewsWire.xcodeproj/project.pbxproj | 24 +++++ 6 files changed, 409 insertions(+), 42 deletions(-) create mode 100644 Mac/MainWindow/OPML/ExportOPMLSheet.xib create mode 100644 Mac/MainWindow/OPML/ExportOPMLWindowController.swift create mode 100644 Mac/MainWindow/OPML/ImportOPMLSheet.xib create mode 100644 Mac/MainWindow/OPML/ImportOPMLWindowController.swift diff --git a/Mac/AppDelegate.swift b/Mac/AppDelegate.swift index 44570bdce..f1b7d87e6 100644 --- a/Mac/AppDelegate.swift +++ b/Mac/AppDelegate.swift @@ -51,6 +51,8 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, private var mainWindowController: MainWindowController? private var addFeedController: AddFeedController? private var addFolderWindowController: AddFolderWindowController? + private var importOPMLController: ImportOPMLWindowController? + private var exportOPMLController: ExportOPMLWindowController? private var keyboardShortcutsWindowController: WebViewWindowController? private var inspectorWindowController: InspectorWindowController? private var crashReportWindowController: CrashReportWindowController? // For testing only @@ -362,54 +364,26 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSUserInterfaceValidations, @IBAction func importOPMLFromFile(_ sender: Any?) { - let panel = NSOpenPanel() - panel.canDownloadUbiquitousContents = true - panel.canResolveUbiquitousConflicts = true - panel.canChooseFiles = true - panel.allowsMultipleSelection = false - panel.canChooseDirectories = false - panel.resolvesAliases = true - panel.allowedFileTypes = ["opml", "xml"] - panel.allowsOtherFileTypes = false - - let result = panel.runModal() - if result == NSApplication.ModalResponse.OK, let url = panel.url { - DispatchQueue.main.async { - do { - try OPMLImporter.parseAndImport(fileURL: url, account: AccountManager.shared.defaultAccount) - } - catch let error as NSError { - NSApplication.shared.presentError(error) - } - } + createAndShowMainWindow() + if mainWindowController!.isDisplayingSheet { + return } + + importOPMLController = ImportOPMLWindowController() + importOPMLController?.runSheetOnWindow(mainWindowController!.window!) + } @IBAction func exportOPML(_ sender: Any?) { - let panel = NSSavePanel() - panel.allowedFileTypes = ["opml"] - panel.allowsOtherFileTypes = false - panel.prompt = NSLocalizedString("Export OPML", comment: "Export OPML") - panel.title = NSLocalizedString("Export OPML", comment: "Export OPML") - panel.nameFieldLabel = NSLocalizedString("Export to:", comment: "Export OPML") - panel.message = NSLocalizedString("Choose a location for the exported OPML file.", comment: "Export OPML") - panel.isExtensionHidden = false - panel.nameFieldStringValue = "MySubscriptions.opml" - - let result = panel.runModal() - if result == NSApplication.ModalResponse.OK, let url = panel.url { - DispatchQueue.main.async { - let filename = url.lastPathComponent - let opmlString = OPMLExporter.OPMLString(with: AccountManager.shared.defaultAccount, title: filename) - do { - try opmlString.write(to: url, atomically: true, encoding: String.Encoding.utf8) - } - catch let error as NSError { - NSApplication.shared.presentError(error) - } - } + createAndShowMainWindow() + if mainWindowController!.isDisplayingSheet { + return } + + exportOPMLController = ExportOPMLWindowController() + exportOPMLController?.runSheetOnWindow(mainWindowController!.window!) + } @IBAction func addAppNews(_ sender: Any?) { diff --git a/Mac/MainWindow/OPML/ExportOPMLSheet.xib b/Mac/MainWindow/OPML/ExportOPMLSheet.xib new file mode 100644 index 000000000..ac2db2a7f --- /dev/null +++ b/Mac/MainWindow/OPML/ExportOPMLSheet.xib @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/MainWindow/OPML/ExportOPMLWindowController.swift b/Mac/MainWindow/OPML/ExportOPMLWindowController.swift new file mode 100644 index 000000000..fd6ba4650 --- /dev/null +++ b/Mac/MainWindow/OPML/ExportOPMLWindowController.swift @@ -0,0 +1,85 @@ +// +// ExportOPMLWindowController.swift +// NetNewsWire +// +// Created by Maurice Parker on 5/1/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import AppKit +import Account + +class ExportOPMLWindowController: NSWindowController { + + @IBOutlet weak var accountPopUpButton: NSPopUpButton! + private weak var hostWindow: NSWindow? + + convenience init() { + self.init(windowNibName: NSNib.Name("ExportOPMLSheet")) + } + + override func windowDidLoad() { + + accountPopUpButton.removeAllItems() + let menu = NSMenu() + for oneAccount in AccountManager.shared.sortedAccounts { + let oneMenuItem = NSMenuItem() + oneMenuItem.title = oneAccount.nameForDisplay + oneMenuItem.representedObject = oneAccount + menu.addItem(oneMenuItem) + } + accountPopUpButton.menu = menu + + } + + // MARK: API + + func runSheetOnWindow(_ hostWindow: NSWindow) { + self.hostWindow = hostWindow + hostWindow.beginSheet(window!) + } + + // MARK: Actions + + @IBAction func cancel(_ sender: Any) { + hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel) + } + + @IBAction func exportOPML(_ sender: Any) { + + guard let menuItem = accountPopUpButton.selectedItem else { + return + } + let account = menuItem.representedObject as! Account + + hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK) + + let panel = NSSavePanel() + panel.allowedFileTypes = ["opml"] + panel.allowsOtherFileTypes = false + panel.prompt = NSLocalizedString("Export OPML", comment: "Export OPML") + panel.title = NSLocalizedString("Export OPML", comment: "Export OPML") + panel.nameFieldLabel = NSLocalizedString("Export to:", comment: "Export OPML") + panel.message = NSLocalizedString("Choose a location for the exported OPML file.", comment: "Export OPML") + panel.isExtensionHidden = false + panel.nameFieldStringValue = "MySubscriptions.opml" + + panel.beginSheetModal(for: hostWindow!) { result in + if result == NSApplication.ModalResponse.OK, let url = panel.url { + DispatchQueue.main.async { + let filename = url.lastPathComponent + let opmlString = OPMLExporter.OPMLString(with: account, title: filename) + do { + try opmlString.write(to: url, atomically: true, encoding: String.Encoding.utf8) + } + catch let error as NSError { + NSApplication.shared.presentError(error) + } + } + } + } + + + + } +} diff --git a/Mac/MainWindow/OPML/ImportOPMLSheet.xib b/Mac/MainWindow/OPML/ImportOPMLSheet.xib new file mode 100644 index 000000000..14b0dded9 --- /dev/null +++ b/Mac/MainWindow/OPML/ImportOPMLSheet.xib @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Mac/MainWindow/OPML/ImportOPMLWindowController.swift b/Mac/MainWindow/OPML/ImportOPMLWindowController.swift new file mode 100644 index 000000000..355912c46 --- /dev/null +++ b/Mac/MainWindow/OPML/ImportOPMLWindowController.swift @@ -0,0 +1,82 @@ +// +// ImportOPMLWindowController.swift +// NetNewsWire +// +// Created by Maurice Parker on 5/1/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import AppKit +import Account + +class ImportOPMLWindowController: NSWindowController { + + @IBOutlet weak var accountPopUpButton: NSPopUpButton! + private weak var hostWindow: NSWindow? + + convenience init() { + self.init(windowNibName: NSNib.Name("ImportOPMLSheet")) + } + + override func windowDidLoad() { + + accountPopUpButton.removeAllItems() + let menu = NSMenu() + for oneAccount in AccountManager.shared.sortedAccounts { + let oneMenuItem = NSMenuItem() + oneMenuItem.title = oneAccount.nameForDisplay + oneMenuItem.representedObject = oneAccount + menu.addItem(oneMenuItem) + } + accountPopUpButton.menu = menu + + } + + // MARK: API + + func runSheetOnWindow(_ hostWindow: NSWindow) { + self.hostWindow = hostWindow + hostWindow.beginSheet(window!) + } + + // MARK: Actions + + @IBAction func cancel(_ sender: Any) { + hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.cancel) + } + + @IBAction func importOPML(_ sender: Any) { + + guard let menuItem = accountPopUpButton.selectedItem else { + return + } + let account = menuItem.representedObject as! Account + + hostWindow!.endSheet(window!, returnCode: NSApplication.ModalResponse.OK) + + let panel = NSOpenPanel() + panel.canDownloadUbiquitousContents = true + panel.canResolveUbiquitousConflicts = true + panel.canChooseFiles = true + panel.allowsMultipleSelection = false + panel.canChooseDirectories = false + panel.resolvesAliases = true + panel.allowedFileTypes = ["opml", "xml"] + panel.allowsOtherFileTypes = false + + panel.beginSheetModal(for: hostWindow!) { result in + if result == NSApplication.ModalResponse.OK, let url = panel.url { + DispatchQueue.main.async { + do { + try OPMLImporter.parseAndImport(fileURL: url, account: account) + } + catch let error as NSError { + NSApplication.shared.presentError(error) + } + } + } + } + + } + +} diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index 382d17364..d28f8ecc3 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -20,6 +20,10 @@ 5144EA2F2279FAB600D19003 /* AccountsDetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA2E2279FAB600D19003 /* AccountsDetailViewController.swift */; }; 5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA352279FC3D00D19003 /* AccountsAddLocal.xib */; }; 5144EA382279FC6200D19003 /* AccountsAddLocalWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA372279FC6200D19003 /* AccountsAddLocalWindowController.swift */; }; + 5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA3A227A379E00D19003 /* ImportOPMLSheet.xib */; }; + 5144EA3D227A37AF00D19003 /* ExportOPMLSheet.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5144EA3C227A37AF00D19003 /* ExportOPMLSheet.xib */; }; + 5144EA40227A37EC00D19003 /* ImportOPMLWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA3E227A37EC00D19003 /* ImportOPMLWindowController.swift */; }; + 5144EA43227A380F00D19003 /* ExportOPMLWindowController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */; }; 5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; }; 5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; }; 5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; }; @@ -642,6 +646,10 @@ 5144EA2E2279FAB600D19003 /* AccountsDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccountsDetailViewController.swift; sourceTree = ""; }; 5144EA352279FC3D00D19003 /* AccountsAddLocal.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = AccountsAddLocal.xib; sourceTree = ""; }; 5144EA372279FC6200D19003 /* AccountsAddLocalWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountsAddLocalWindowController.swift; sourceTree = ""; }; + 5144EA3A227A379E00D19003 /* ImportOPMLSheet.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ImportOPMLSheet.xib; sourceTree = ""; }; + 5144EA3C227A37AF00D19003 /* ExportOPMLSheet.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ExportOPMLSheet.xib; sourceTree = ""; }; + 5144EA3E227A37EC00D19003 /* ImportOPMLWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImportOPMLWindowController.swift; sourceTree = ""; }; + 5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExportOPMLWindowController.swift; sourceTree = ""; }; 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = ""; }; 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = ""; }; 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = ""; }; @@ -960,6 +968,17 @@ path = Tree; sourceTree = ""; }; + 5144EA39227A377700D19003 /* OPML */ = { + isa = PBXGroup; + children = ( + 5144EA3A227A379E00D19003 /* ImportOPMLSheet.xib */, + 5144EA3E227A37EC00D19003 /* ImportOPMLWindowController.swift */, + 5144EA3C227A37AF00D19003 /* ExportOPMLSheet.xib */, + 5144EA42227A380F00D19003 /* ExportOPMLWindowController.swift */, + ); + path = OPML; + sourceTree = ""; + }; 5183CCDB226F1EEB0010922C /* Progress */ = { isa = PBXGroup; children = ( @@ -1177,6 +1196,7 @@ 849A977C1ED9EC42007D329B /* Detail */, 849A97551ED9EAC3007D329B /* Add Feed */, 849A97411ED9EAA9007D329B /* Add Folder */, + 5144EA39227A377700D19003 /* OPML */, ); path = MainWindow; sourceTree = ""; @@ -2173,9 +2193,11 @@ 84C9FC7D22629E1200D921D6 /* AccountsDetail.xib in Resources */, 5144EA362279FC3D00D19003 /* AccountsAddLocal.xib in Resources */, 84C9FC8C22629E8F00D921D6 /* KeyboardShortcuts.html in Resources */, + 5144EA3B227A379E00D19003 /* ImportOPMLSheet.xib in Resources */, 844B5B691FEA20DF00C7C76A /* SidebarKeyboardShortcuts.plist in Resources */, 84A3EE5F223B667F00557320 /* DefaultFeeds.opml in Resources */, 84C9FC8222629E4800D921D6 /* Preferences.storyboard in Resources */, + 5144EA3D227A37AF00D19003 /* ExportOPMLSheet.xib in Resources */, 849C64681ED37A5D003D8FC0 /* Assets.xcassets in Resources */, 848362FD2262A30800DA1D35 /* styleSheet.css in Resources */, 8483630B2262A3F000DA1D35 /* RenameSheet.xib in Resources */, @@ -2388,6 +2410,7 @@ 849A97891ED9ECEF007D329B /* ArticleStyle.swift in Sources */, 84FF69B11FC3793300DC198E /* FaviconURLFinder.swift in Sources */, 84B7178C201E66580091657D /* SidebarViewController+ContextualMenus.swift in Sources */, + 5144EA43227A380F00D19003 /* ExportOPMLWindowController.swift in Sources */, 842611A21FCB769D0086A189 /* RSHTMLMetadata+Extension.swift in Sources */, 84A1500520048DDF0046AD9A /* SendToMarsEditCommand.swift in Sources */, D5907DB22004BB37005947E5 /* ScriptingObjectContainer.swift in Sources */, @@ -2442,6 +2465,7 @@ 849A977B1ED9EC04007D329B /* UnreadIndicatorView.swift in Sources */, 84B99C9D1FAE83C600ECDEDB /* DeleteCommand.swift in Sources */, 849A97541ED9EAC0007D329B /* AddFeedWindowController.swift in Sources */, + 5144EA40227A37EC00D19003 /* ImportOPMLWindowController.swift in Sources */, 849A976D1ED9EBC8007D329B /* TimelineTableView.swift in Sources */, 84D52E951FE588BB00D14F5B /* DetailStatusBarView.swift in Sources */, D5E4CC64202C1AC1009B4FFC /* MainWindowController+Scriptability.swift in Sources */,