Reputation: 245
I'm trying to expand all children starting on root(parent of a parent....) until the actual node. How can I do it without clicking on every node?
I'm using it to show directories content and I would like to show the last path the user was before closing/opening the app.
The first picture shows how I would like it to be and the second picture shows what is shown at the moment.
The code is not done. There is a lot of testing and debugging.
I added all relevant code to this questions.
So far my app reads directories and if there is any mp3 file on this directory it is shown on a table view, but it is not part of my question, just a background.
extension ViewController: NSOutlineViewDataSource {
func outlineView(_ outlineView: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int {
let directoryItem = item as? DirectoryItem ?? rootItem
return directoryItem.childItems.count
}
func outlineView(_ outlineView: NSOutlineView, child index: Int, ofItem item: Any?) -> Any {
let directoryItem = item as? DirectoryItem ?? rootItem
return directoryItem.childItems[index]
}
func outlineView(_ outlineView: NSOutlineView, isItemExpandable item: Any) -> Bool {
let directoryItem = item as? DirectoryItem ?? rootItem
return directoryItem.isExpandable
}
}
extension ViewController: NSOutlineViewDelegate {
func outlineViewSelectionDidChange(_ notification: Notification) {
singleClick()
}
func outlineView(_ outlineView: NSOutlineView, shouldExpandItem item: Any) -> Bool {
let directoryItem = item as? DirectoryItem ?? rootItem
return (directoryItem.childItems.count != 0)
}
func outlineView(_ outlineView: NSOutlineView, shouldShowOutlineCellForItem item: Any) -> Bool {
let directoryItem = item as? DirectoryItem ?? rootItem
return (directoryItem.childItems.count != 0)
}
func outlineView(_ outlineView: NSOutlineView, viewFor tableColumn: NSTableColumn?, item: Any) -> NSView? {
var text = ""
if let directories = item as? DirectoryItem {
if(directories.isdir) {
text = directories.name
let tableCell = outlineView.makeView(withIdentifier: NSUserInterfaceItemIdentifier(rawValue: "cell"), owner: self) as! NSTableCellView
tableCell.textField!.stringValue = text
return tableCell
}
}
return nil
}
}
@objc func singleClick()
{
if let item = self.outlineView.item(atRow: self.outlineView.selectedRow) {
self.arrMp3File.removeAll()
do {
let xx = (item as! DirectoryItem).url
let b = self.getSubDir(path: xx.path)
self.saveDefaults(url: xx)
DispatchQueue.global(qos: .background).async { [weak self] in
DispatchQueue.main.async {
self?.progressIndicator.isHidden = false
self?.progressIndicator.startAnimation(self)
}
for bb in b {
self?.getTagsFromFile(file: xx.path+"/"+bb)
}
DispatchQueue.main.async {
self?.arrMp3File.sort(by: {
$0.file < $1.file
})
self?.tableView.reloadData()
self?.loadTagsFromButton.isEnabled = true
self?.progressIndicator.stopAnimation(self)
self?.progressIndicator.isHidden = true
}
}
}
}
}
override func viewDidLoad() {
super.viewDidLoad()
let defaults = UserDefaults.standard
let lastDirectory = defaults.url(forKey: "LastDirectory")
print(lastDirectory ?? "")
// rootItem = DirectoryItem(url: lastDirectory ?? FileManager.default.homeDirectoryForCurrentUser)
// getDir(path: age)
outlineView.dataSource = self
outlineView.delegate = self
tableView.delegate = self
tableView.dataSource = self
tableView.doubleAction = #selector(doubleClickOnResultRow)
// outlineView.action = #selector(singleClick)
self.progressIndicator.isHidden = true
self.tableView.reloadData()
}
class Directories {
var name: String
var subDirectories: [String]
init(name: String, subDirectories: [String]) {
self.name = name
self.subDirectories = subDirectories
}
}
class DirectoryItem {
var name: String
var url: URL
var isdir: Bool
var prev: URL
lazy var isExpandable: Bool = {
do {
return try url.resourceValues(forKeys: [.isDirectoryKey]).isDirectory ?? false
} catch let error as NSError {
return false
}
}()
lazy var childItems: [DirectoryItem] = {
do {
let urls = try FileManager.default.contentsOfDirectory(at: url,
includingPropertiesForKeys: [.isDirectoryKey],
options: [.skipsHiddenFiles])
var aa: [DirectoryItem]
var bb: [DirectoryItem]
bb = []
aa = urls.map { DirectoryItem(url: $0) }
for a in aa {
if(a.isdir) {
bb.append(a)
// print(a)
}
}
return bb
//return urls.map { DirectoryItem(url: $0) }
} catch let error as NSError {
return []
}
}()
init(url: URL) {
self.url = url
self.name = url.lastPathComponent
self.isdir = url.hasDirectoryPath
self.prev = url.deletingLastPathComponent()
}
}
Upvotes: 1
Views: 386
Reputation: 385620
If you have saved the URL that the user was last visiting, then you can show and select it in three steps:
Convert the URL to an array of DirectoryItem
representing the path components of the URL.
Ask the outline view to expand each of those items, starting with the item that is a direct child of the root node.
Ask the outline view to select the last item.
Untested code:
func reveal(_ url: URL) {
// Step 1.
let items = itemHierarchy(for: url)
// Step 2.
for item in items {
outlineView.expandItem(item)
}
// Step 3.
if
let last = items.last,
case let row = outlineView.row(forItem: last),
row != -1
{
let set = IndexSet(integer: row)
outlineView.selectRowIndexes(set, byExtendingSelection: false)
}
}
private func itemHierarchy(for url: URL) -> [DirectoryItem] {
var items: [DirectoryItem] = []
var current: DirectoryItem = rootItem
for component in url.pathComponents {
guard let child = current.childItems.first(where: { $0.name == component }) else {
return items
}
items.append(child)
current = child
}
return items
}
Upvotes: 1