mirror of
https://github.com/ksherlock/ample.git
synced 2024-06-10 00:29:55 +00:00
bookmark manager
This commit is contained in:
parent
0f3e6c8307
commit
4baf545245
|
@ -64,6 +64,8 @@
|
||||||
B6152B5B25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
B6152B5B25F5B57E00605E6E /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = B6152B5925F5B57E00605E6E /* Media.m */; };
|
||||||
B615A99F26640940001FBF99 /* SlotView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6E9A18125088B36005E7525 /* SlotView.xib */; };
|
B615A99F26640940001FBF99 /* SlotView.xib in Resources */ = {isa = PBXBuildFile; fileRef = B6E9A18125088B36005E7525 /* SlotView.xib */; };
|
||||||
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E9A17F25088B1B005E7525 /* SlotViewController.m */; };
|
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = B6E9A17F25088B1B005E7525 /* SlotViewController.m */; };
|
||||||
|
B63005332666D6940014C381 /* BookmarkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63005322666D6940014C381 /* BookmarkManager.m */; };
|
||||||
|
B63005342666D6940014C381 /* BookmarkManager.m in Sources */ = {isa = PBXBuildFile; fileRef = B63005322666D6940014C381 /* BookmarkManager.m */; };
|
||||||
B6374AC4260EBBCF0045CA16 /* pty_shell.c in Sources */ = {isa = PBXBuildFile; fileRef = B6374AB6260EBB970045CA16 /* pty_shell.c */; };
|
B6374AC4260EBBCF0045CA16 /* pty_shell.c in Sources */ = {isa = PBXBuildFile; fileRef = B6374AB6260EBB970045CA16 /* pty_shell.c */; };
|
||||||
B6374AC5260EBC5A0045CA16 /* pty_shell in CopyFiles */ = {isa = PBXBuildFile; fileRef = B6374ABD260EBBC90045CA16 /* pty_shell */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
B6374AC5260EBC5A0045CA16 /* pty_shell in CopyFiles */ = {isa = PBXBuildFile; fileRef = B6374ABD260EBBC90045CA16 /* pty_shell */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; };
|
||||||
B6374AD1260ECB400045CA16 /* macclas2.plist in Resources */ = {isa = PBXBuildFile; fileRef = B6374AC9260ECB3F0045CA16 /* macclas2.plist */; };
|
B6374AD1260ECB400045CA16 /* macclas2.plist in Resources */ = {isa = PBXBuildFile; fileRef = B6374AC9260ECB3F0045CA16 /* macclas2.plist */; };
|
||||||
|
@ -375,6 +377,8 @@
|
||||||
B6152B5525F4549F00605E6E /* Slot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Slot.m; sourceTree = "<group>"; };
|
B6152B5525F4549F00605E6E /* Slot.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Slot.m; sourceTree = "<group>"; };
|
||||||
B6152B5825F5B4F100605E6E /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
|
B6152B5825F5B4F100605E6E /* Media.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Media.h; sourceTree = "<group>"; };
|
||||||
B6152B5925F5B57E00605E6E /* Media.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = "<group>"; };
|
B6152B5925F5B57E00605E6E /* Media.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = Media.m; sourceTree = "<group>"; };
|
||||||
|
B63005312666D6940014C381 /* BookmarkManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BookmarkManager.h; sourceTree = "<group>"; };
|
||||||
|
B63005322666D6940014C381 /* BookmarkManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BookmarkManager.m; sourceTree = "<group>"; };
|
||||||
B6374AB6260EBB970045CA16 /* pty_shell.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pty_shell.c; sourceTree = "<group>"; };
|
B6374AB6260EBB970045CA16 /* pty_shell.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pty_shell.c; sourceTree = "<group>"; };
|
||||||
B6374ABD260EBBC90045CA16 /* pty_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pty_shell; sourceTree = BUILT_PRODUCTS_DIR; };
|
B6374ABD260EBBC90045CA16 /* pty_shell */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = pty_shell; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
B6374AC9260ECB3F0045CA16 /* macclas2.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = macclas2.plist; sourceTree = "<group>"; };
|
B6374AC9260ECB3F0045CA16 /* macclas2.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = macclas2.plist; sourceTree = "<group>"; };
|
||||||
|
@ -690,6 +694,8 @@
|
||||||
B608E17E2502FE0C00D53465 /* TransparentScroller.m */,
|
B608E17E2502FE0C00D53465 /* TransparentScroller.m */,
|
||||||
B66D0FE62611386B000902F1 /* SoftwareList.m */,
|
B66D0FE62611386B000902F1 /* SoftwareList.m */,
|
||||||
B66D0FE926113AA8000902F1 /* SoftwareList.h */,
|
B66D0FE926113AA8000902F1 /* SoftwareList.h */,
|
||||||
|
B63005312666D6940014C381 /* BookmarkManager.h */,
|
||||||
|
B63005322666D6940014C381 /* BookmarkManager.m */,
|
||||||
B6BA563A251685DA00B0C47D /* Window Controllers */,
|
B6BA563A251685DA00B0C47D /* Window Controllers */,
|
||||||
B6B9EA652506A5550080E70D /* EjectButton.h */,
|
B6B9EA652506A5550080E70D /* EjectButton.h */,
|
||||||
B6B9EA642506A5550080E70D /* EjectButton.m */,
|
B6B9EA642506A5550080E70D /* EjectButton.m */,
|
||||||
|
@ -1154,6 +1160,7 @@
|
||||||
B60A6E1424EE0AE2004B7EEF /* FlippedView.m in Sources */,
|
B60A6E1424EE0AE2004B7EEF /* FlippedView.m in Sources */,
|
||||||
B6BA258024E99BE9005FB8FF /* AppDelegate.m in Sources */,
|
B6BA258024E99BE9005FB8FF /* AppDelegate.m in Sources */,
|
||||||
B6004DF024FB05D600D38596 /* LogWindowController.m in Sources */,
|
B6004DF024FB05D600D38596 /* LogWindowController.m in Sources */,
|
||||||
|
B63005332666D6940014C381 /* BookmarkManager.m in Sources */,
|
||||||
B66236A924FD9A34006CABD7 /* PreferencesWindowController.m in Sources */,
|
B66236A924FD9A34006CABD7 /* PreferencesWindowController.m in Sources */,
|
||||||
B63C1F0F25B1447C0016A611 /* CheatSheetWindowController.m in Sources */,
|
B63C1F0F25B1447C0016A611 /* CheatSheetWindowController.m in Sources */,
|
||||||
B64AF1F2250ECB2E00A09B9B /* DiskImagesWindowController.m in Sources */,
|
B64AF1F2250ECB2E00A09B9B /* DiskImagesWindowController.m in Sources */,
|
||||||
|
@ -1183,6 +1190,7 @@
|
||||||
B6E4B5B324FDE2670094A35C /* MediaViewController.m in Sources */,
|
B6E4B5B324FDE2670094A35C /* MediaViewController.m in Sources */,
|
||||||
B64AF1F7250ED5E400A09B9B /* TableCellView.m in Sources */,
|
B64AF1F7250ED5E400A09B9B /* TableCellView.m in Sources */,
|
||||||
B6E4B5B424FDE2670094A35C /* FlippedView.m in Sources */,
|
B6E4B5B424FDE2670094A35C /* FlippedView.m in Sources */,
|
||||||
|
B63005342666D6940014C381 /* BookmarkManager.m in Sources */,
|
||||||
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */,
|
B615A9A026640A70001FBF99 /* SlotViewController.m in Sources */,
|
||||||
B6665C15265A0E3E00254939 /* AutocompleteControl.m in Sources */,
|
B6665C15265A0E3E00254939 /* AutocompleteControl.m in Sources */,
|
||||||
B6E4B5B524FDE2670094A35C /* AppDelegate.m in Sources */,
|
B6E4B5B524FDE2670094A35C /* AppDelegate.m in Sources */,
|
||||||
|
|
34
Ample/BookmarkManager.h
Normal file
34
Ample/BookmarkManager.h
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
//
|
||||||
|
// BookmarkManager.h
|
||||||
|
// Ample
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 6/1/2021.
|
||||||
|
// Copyright © 2021 Kelvin Sherlock. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
|
||||||
|
@class NSMenu;
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_BEGIN
|
||||||
|
|
||||||
|
@interface BookmarkManager : NSObject
|
||||||
|
|
||||||
|
@property (weak) IBOutlet NSMenu *menu;
|
||||||
|
|
||||||
|
+(instancetype)sharedManager;
|
||||||
|
|
||||||
|
-(void)loadBookmarks;
|
||||||
|
-(void)updateMenu;
|
||||||
|
|
||||||
|
-(BOOL)validateName: (NSString *)name;
|
||||||
|
|
||||||
|
-(BOOL)saveBookmark: (NSDictionary *)bookmark name: (NSString *)name;
|
||||||
|
-(NSDictionary *)loadBookmarkFromURL: (NSURL *)url;
|
||||||
|
|
||||||
|
-(BOOL)saveDefault: (NSDictionary *)bookmark;
|
||||||
|
-(NSDictionary *)loadDefault;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
NS_ASSUME_NONNULL_END
|
214
Ample/BookmarkManager.m
Normal file
214
Ample/BookmarkManager.m
Normal file
|
@ -0,0 +1,214 @@
|
||||||
|
//
|
||||||
|
// BookmarkManager.m
|
||||||
|
// Ample
|
||||||
|
//
|
||||||
|
// Created by Kelvin Sherlock on 6/1/2021.
|
||||||
|
// Copyright © 2021 Kelvin Sherlock. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#import "BookmarkManager.h"
|
||||||
|
#import "Ample.h"
|
||||||
|
|
||||||
|
@interface BookmarkManager () {
|
||||||
|
NSArray<NSURL *> *_urls;
|
||||||
|
NSURL *_bookmarkDirectory;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
@implementation BookmarkManager
|
||||||
|
|
||||||
|
static BookmarkManager *singleton = nil;
|
||||||
|
|
||||||
|
-(void)awakeFromNib {
|
||||||
|
if (!singleton) singleton = self;
|
||||||
|
}
|
||||||
|
|
||||||
|
+(instancetype)sharedManager {
|
||||||
|
if (!singleton) singleton = [BookmarkManager new];
|
||||||
|
return singleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(instancetype)init {
|
||||||
|
if (singleton) return singleton;
|
||||||
|
return [super init];
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSURL *)bookmarkDirectory {
|
||||||
|
|
||||||
|
if (_bookmarkDirectory) return _bookmarkDirectory;
|
||||||
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
NSURL *url = SupportDirectory();
|
||||||
|
url = [url URLByAppendingPathComponent: @"Bookmarks"];
|
||||||
|
NSError *error = nil;
|
||||||
|
[fm createDirectoryAtURL: url withIntermediateDirectories: YES attributes: nil error: &error];
|
||||||
|
if (error) NSLog(@"%@", error);
|
||||||
|
_bookmarkDirectory = url;
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disallow leading .
|
||||||
|
* disallow : or / characters.
|
||||||
|
*/
|
||||||
|
-(BOOL)validateName: (NSString *)name {
|
||||||
|
|
||||||
|
enum { kMaxLength = 128 };
|
||||||
|
unichar buffer[kMaxLength];
|
||||||
|
NSUInteger length = [name length];
|
||||||
|
if (length == 0 || length > kMaxLength) return NO;
|
||||||
|
[name getCharacters: buffer range: NSMakeRange(0, length)];
|
||||||
|
if (buffer[0] == '.') return NO;
|
||||||
|
for (unsigned i = 0; i < length; ++i) {
|
||||||
|
unichar c = buffer[i];
|
||||||
|
if (c == ':' || c == '/') return NO;
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(NSDictionary *)loadDefault {
|
||||||
|
NSURL *url = [self bookmarkDirectory];
|
||||||
|
url = [url URLByAppendingPathComponent: @".Default"];
|
||||||
|
|
||||||
|
NSDictionary *d;
|
||||||
|
|
||||||
|
if (@available(macOS 10.13, *)) {
|
||||||
|
NSError *error = nil;
|
||||||
|
d = [NSDictionary dictionaryWithContentsOfURL: url error: &error];
|
||||||
|
if (!d) NSLog(@"Error loading %@: %@", url, error);
|
||||||
|
} else {
|
||||||
|
d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||||
|
if (!d) NSLog(@"Error loading %@", url);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* save as .Default */
|
||||||
|
-(BOOL)saveDefault: (NSDictionary *)bookmark {
|
||||||
|
|
||||||
|
NSURL *url = [self bookmarkDirectory];
|
||||||
|
url = [url URLByAppendingPathComponent: @".Default"];
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
BOOL ok = NO;
|
||||||
|
if (@available(macOS 10.13, *)) {
|
||||||
|
ok = [bookmark writeToURL: url error: &error];
|
||||||
|
if (!ok) NSLog(@"%@", error);
|
||||||
|
} else {
|
||||||
|
ok = [bookmark writeToURL: url atomically: YES];
|
||||||
|
}
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(BOOL)saveBookmark: (NSDictionary *)bookmark name: (NSString *)name {
|
||||||
|
|
||||||
|
NSError *error;
|
||||||
|
NSData *data = [NSPropertyListSerialization dataWithPropertyList: bookmark
|
||||||
|
format: NSPropertyListXMLFormat_v1_0
|
||||||
|
options: 0
|
||||||
|
error: &error];
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
NSURL *base = [self bookmarkDirectory];
|
||||||
|
|
||||||
|
NSURL *url = [base URLByAppendingPathComponent: name];
|
||||||
|
|
||||||
|
BOOL ok = [data writeToURL: url options: NSDataWritingWithoutOverwriting error: &error];
|
||||||
|
|
||||||
|
if (!ok) {
|
||||||
|
for (unsigned i = 1 ; i < 100; ++i) {
|
||||||
|
NSString *tmp = [name stringByAppendingFormat: @"(%d)", i];
|
||||||
|
[base URLByAppendingPathComponent: tmp];
|
||||||
|
|
||||||
|
ok = [data writeToURL: url options: NSDataWritingWithoutOverwriting error: &error];
|
||||||
|
if (ok) {
|
||||||
|
name = tmp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ok) return NO;
|
||||||
|
|
||||||
|
if (!_menu) return YES; // ?
|
||||||
|
|
||||||
|
NSUInteger ix = [_urls indexOfObjectPassingTest: ^BOOL(NSURL *object, NSUInteger index, BOOL *stop){
|
||||||
|
NSString *path = [object lastPathComponent];
|
||||||
|
return [name caseInsensitiveCompare: path] == NSOrderedAscending;
|
||||||
|
}];
|
||||||
|
|
||||||
|
NSMenuItem *item = [[NSMenuItem alloc] initWithTitle: name action: @selector(loadBookmark:) keyEquivalent: @""];
|
||||||
|
[item setRepresentedObject: url];
|
||||||
|
|
||||||
|
if (ix == NSNotFound) {
|
||||||
|
_urls = [_urls arrayByAddingObject: url];
|
||||||
|
[_menu addItem: item];
|
||||||
|
} else {
|
||||||
|
|
||||||
|
NSInteger n = [_menu numberOfItems];
|
||||||
|
[_menu insertItem: item atIndex: n - [_urls count] + ix];
|
||||||
|
NSMutableArray *tmp = [_urls mutableCopy];
|
||||||
|
|
||||||
|
[tmp insertObject: url atIndex: ix];
|
||||||
|
}
|
||||||
|
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(NSDictionary *)loadBookmarkFromURL: (NSURL *)url {
|
||||||
|
|
||||||
|
NSDictionary *d;
|
||||||
|
|
||||||
|
if (@available(macOS 10.13, *)) {
|
||||||
|
NSError *error = nil;
|
||||||
|
d = [NSDictionary dictionaryWithContentsOfURL: url error: &error];
|
||||||
|
if (!d) NSLog(@"Error loading %@: %@", url, error);
|
||||||
|
} else {
|
||||||
|
d = [NSDictionary dictionaryWithContentsOfURL: url];
|
||||||
|
if (!d) NSLog(@"Error loading %@", url);
|
||||||
|
}
|
||||||
|
return d;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-(void)loadBookmarks {
|
||||||
|
|
||||||
|
NSURL *url = [self bookmarkDirectory];
|
||||||
|
|
||||||
|
NSFileManager *fm = [NSFileManager defaultManager];
|
||||||
|
|
||||||
|
NSError *error = nil;
|
||||||
|
|
||||||
|
NSArray *files = [fm contentsOfDirectoryAtURL: url
|
||||||
|
includingPropertiesForKeys: nil
|
||||||
|
options: NSDirectoryEnumerationSkipsHiddenFiles
|
||||||
|
error: &error];
|
||||||
|
|
||||||
|
// bleh, has to create 2 new NSStrings for every comparison
|
||||||
|
files = [files sortedArrayUsingComparator: ^(NSURL *a, NSURL *b){
|
||||||
|
NSString *aa = [a lastPathComponent];
|
||||||
|
NSString *bb = [b lastPathComponent];
|
||||||
|
return [aa caseInsensitiveCompare: bb];
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
_urls = files;
|
||||||
|
}
|
||||||
|
|
||||||
|
-(void)updateMenu {
|
||||||
|
|
||||||
|
NSArray *menus = [_menu itemArray];
|
||||||
|
for (NSMenuItem *item in [menus reverseObjectEnumerator]) {
|
||||||
|
if ([item tag] == 0xdeadbeef) [_menu removeItem: item];
|
||||||
|
}
|
||||||
|
for (NSURL *url in _urls) {
|
||||||
|
NSString *title = [url lastPathComponent]; // [[url lastPathComponent] stringByDeletingPathExtension];
|
||||||
|
|
||||||
|
NSMenuItem *item = [_menu addItemWithTitle: title action: @selector(loadBookmark:) keyEquivalent: @""];
|
||||||
|
[item setRepresentedObject: url];
|
||||||
|
[item setTag: 0xdeadbeef];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
Loading…
Reference in New Issue
Block a user