diff --git a/Evergreen.xcodeproj/project.pbxproj b/Evergreen.xcodeproj/project.pbxproj index 31dea7366..c8c5cc015 100644 --- a/Evergreen.xcodeproj/project.pbxproj +++ b/Evergreen.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */; }; 842E45E71ED8C747000A8B52 /* DB5.plist in Resources */ = {isa = PBXBuildFile; fileRef = 842E45E61ED8C747000A8B52 /* DB5.plist */; }; 84513F901FAA63950023A1A9 /* FeedListControlsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84513F8F1FAA63950023A1A9 /* FeedListControlsView.swift */; }; + 845F52ED1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */; }; 846A7BEC1F872C5600FEFD30 /* BatchUpdate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 846A7BEB1F872C5600FEFD30 /* BatchUpdate.swift */; }; 846E773D1F6EF67A00A165E2 /* Account.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 846E773A1F6EF5D700A165E2 /* Account.framework */; }; 846E773E1F6EF67A00A165E2 /* Account.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 846E773A1F6EF5D700A165E2 /* Account.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; @@ -391,6 +392,7 @@ 842E45E41ED8C6B7000A8B52 /* MainWindowSplitView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MainWindowSplitView.swift; sourceTree = ""; }; 842E45E61ED8C747000A8B52 /* DB5.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = DB5.plist; path = Evergreen/Resources/DB5.plist; sourceTree = ""; }; 84513F8F1FAA63950023A1A9 /* FeedListControlsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedListControlsView.swift; sourceTree = ""; }; + 845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedPasteboardWriter.swift; sourceTree = ""; }; 846A7BEB1F872C5600FEFD30 /* BatchUpdate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BatchUpdate.swift; path = Evergreen/BatchUpdate.swift; sourceTree = ""; }; 846E77161F6EF5D000A165E2 /* Database.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Database.xcodeproj; path = Frameworks/Database/Database.xcodeproj; sourceTree = ""; }; 846E77301F6EF5D600A165E2 /* Account.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = Account.xcodeproj; path = Frameworks/Account/Account.xcodeproj; sourceTree = ""; }; @@ -590,6 +592,7 @@ 849A979E1ED9F130007D329B /* SidebarCell.swift */, 849A97611ED9EB96007D329B /* SidebarTreeControllerDelegate.swift */, 849A97631ED9EB96007D329B /* UnreadCountView.swift */, + 845F52EC1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift */, ); path = Sidebar; sourceTree = ""; @@ -1214,6 +1217,7 @@ 84DAEE321F870B390058304B /* DockBadge.swift in Sources */, 842E45DD1ED8C54B000A8B52 /* Browser.swift in Sources */, 842E45E31ED8C681000A8B52 /* KeyboardDelegateProtocol.swift in Sources */, + 845F52ED1FB2B9FC00C10BF0 /* FeedPasteboardWriter.swift in Sources */, 849A975E1ED9EB72007D329B /* MainWindowController.swift in Sources */, 842E45E51ED8C6B7000A8B52 /* MainWindowSplitView.swift in Sources */, 849A97661ED9EB96007D329B /* SidebarViewController.swift in Sources */, diff --git a/Evergreen/MainWindow/Sidebar/FeedPasteboardWriter.swift b/Evergreen/MainWindow/Sidebar/FeedPasteboardWriter.swift new file mode 100644 index 000000000..de8aa474b --- /dev/null +++ b/Evergreen/MainWindow/Sidebar/FeedPasteboardWriter.swift @@ -0,0 +1,100 @@ +// +// FeedPasteboardWriter.swift +// Evergreen +// +// Created by Brent Simmons on 11/7/17. +// Copyright © 2017 Ranchero Software. All rights reserved. +// + +import Cocoa +import Data + +@objc final class FeedPasteboardWriter: NSObject, NSPasteboardWriting { + + private let feed: Feed + static let feedUTI = "com.ranchero.feed" + static let feedUTIType = NSPasteboard.PasteboardType(rawValue: feedUTI) + static let feedUTIInternal = "com.ranchero.evergreen.internal.feed"; + static let feedUTIInternalType = NSPasteboard.PasteboardType(rawValue: feedUTIInternal) + + init(feed: Feed) { + + self.feed = feed + } + + // MARK: - NSPasteboardWriting + + func writableTypes(for pasteboard: NSPasteboard) -> [NSPasteboard.PasteboardType] { + + return [.string, .URL, FeedPasteboardWriter.feedUTIType, FeedPasteboardWriter.feedUTIInternalType] + } + + func pasteboardPropertyList(forType type: NSPasteboard.PasteboardType) -> Any? { + + let plist: Any? + + switch type { + case .string: + plist = feed.nameForDisplay + case .URL: + plist = feed.url + case FeedPasteboardWriter.feedUTIType: + plist = exportDictionary() + case FeedPasteboardWriter.feedUTIInternalType: + plist = internalDictionary() + default: + plist = nil + } + + return plist + } +} + +private extension FeedPasteboardWriter { + + private struct Key { + + static let url = "URL" + static let homePageURL = "homePageURL" + static let name = "name" + + // Internal + static let accountID = "accountID" + static let feedID = "feedID" + static let editedName = "editedName" + static let unreadCount = "unreadCount" + } + + func exportDictionary() -> [String: String] { + + var d = [String: String]() + + d[Key.url] = feed.url + d[Key.homePageURL] = feed.homePageURL ?? "" + d[Key.name] = feed.nameForDisplay + + return d + } + + func internalDictionary() -> [String: Any] { + + var d = [String: Any]() + + d[Key.url] = feed.url + if let homePageURL = feed.homePageURL { + d[Key.homePageURL] = homePageURL + } + if let name = feed.name { + d[Key.name] = name + } + if let editedName = feed.editedName { + d[Key.editedName] = editedName + } + if feed.unreadCount > 0 { + d[Key.unreadCount] = feed.unreadCount + } + + return d + + } +} diff --git a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift index 3459c8104..ef5cb76f9 100644 --- a/Evergreen/MainWindow/Sidebar/SidebarViewController.swift +++ b/Evergreen/MainWindow/Sidebar/SidebarViewController.swift @@ -27,7 +27,9 @@ import RSCore override func viewDidLoad() { outlineView.sidebarViewController = self - + outlineView.setDraggingSourceOperationMask(.move, forLocal: true) + outlineView.setDraggingSourceOperationMask(.copy, forLocal: false) + NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(userDidAddFeed(_:)), name: .UserDidAddFeed, object: nil) @@ -140,7 +142,7 @@ import RSCore } } - //MARK: NSOutlineViewDataSource + // MARK: NSOutlineViewDataSource func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { @@ -156,6 +158,15 @@ import RSCore return nodeForItem(item as AnyObject?).canHaveChildNodes } + + func outlineView(_ outlineView: NSOutlineView, pasteboardWriterForItem item: Any) -> NSPasteboardWriting? { + + let node = nodeForItem(item as AnyObject?) + if let feed = node.representedObject as? Feed { + return FeedPasteboardWriter(feed: feed) + } + return nil + } } //MARK: - Private diff --git a/Evergreen/MainWindow/Timeline/TimelineViewController.swift b/Evergreen/MainWindow/Timeline/TimelineViewController.swift index 9a6524138..df630e595 100644 --- a/Evergreen/MainWindow/Timeline/TimelineViewController.swift +++ b/Evergreen/MainWindow/Timeline/TimelineViewController.swift @@ -69,7 +69,6 @@ class TimelineViewController: NSViewController, KeyboardDelegate, UndoableComman tableView.target = self tableView.doubleAction = #selector(openArticleInBrowser(_:)) tableView.keyboardDelegate = self - tableView.setDraggingSourceOperationMask(.copy, forLocal: true) tableView.setDraggingSourceOperationMask(.copy, forLocal: false) if !didRegisterForNotifications {