Merge pull request #254 from MarkJerde/various_fixes

Various fixes
This commit is contained in:
Gennadii Potapov 2022-01-24 13:12:24 +08:00 committed by GitHub
commit 696178a7ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 741 additions and 381 deletions

View file

@ -22,7 +22,7 @@
@class SGHotKey;
@interface AppController : NSObject <NSMenuDelegate, NSApplicationDelegate, NSAlertDelegate, FlycutStoreDelegate, FlycutOperatorDelegate, BezelWindowDelegate> {
@interface AppController : NSObject <NSMenuDelegate, NSApplicationDelegate, FlycutStoreDelegate, FlycutOperatorDelegate, BezelWindowDelegate> {
BezelWindow *bezel;
SGHotKey *mainHotKey;
IBOutlet SRRecorderControl *mainRecorder;
@ -45,9 +45,13 @@
NSString *statusItemText;
NSImage *statusItemImage;
IBOutlet NSTextField *savingSectionLabel;
IBOutlet NSTextField *saveFromBezelToLabel;
IBOutlet NSTextField *forgottenItemLabel;
IBOutlet NSButton *forgottenFavoritesCheckbox;
IBOutlet NSButton *forgottenClippingsCheckbox;
IBOutlet NSButton *saveToLocationButton;
IBOutlet NSButton *autoSaveToLocationButton;
// The menu attatched to same
IBOutlet NSMenu *jcMenu;
int jcMenuBaseItemsCount;
@ -75,6 +79,8 @@
BOOL needMenuUpdate;
}
+ (BOOL)isAppSandboxed;
// Basic functionality
-(void) pollPB:(NSTimer *)timer;
-(void) addClipToPasteboard:(NSString*)pbFullText;

View file

@ -26,6 +26,15 @@
@implementation AppController
/// Determines, through a hack of sorts, if the app is running sandboxed. The SANDBOXING define has no direct connection to being sandboxed, but this method identifies the state by looking for a directory which will have at least eight path components if sandboxed and is quite unlikely to have that many if not sandboxed. Of course, if this doesn't work for your unique case, just do a custom build with this method returning NO.
+ (BOOL)isAppSandboxed {
// Get the Desktop directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDesktopDirectory, NSUserDomainMask, YES);
NSString *desktopDirectory = [paths objectAtIndex:0];
return ((NSArray*)[desktopDirectory componentsSeparatedByString:@"/"]).count >= 8;
}
- (id)init
{
[[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys:
@ -134,6 +143,7 @@
- (void)showOldOSXAlert {
// FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if (![AppController isAppSandboxed]) { return; }"
#ifdef SANDBOXING
NSOperatingSystemVersion ver = [[NSProcessInfo processInfo] operatingSystemVersion];
if (ver.majorVersion == 10 && ver.minorVersion <= 13) {
@ -224,6 +234,7 @@
// The load-on-startup check can be really slow, so this will be dispatched out so our thread isn't blocked.
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])"
#ifdef SANDBOXING
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bundleIdentifier == %@", kFlycutHelperId];
NSArray *helperApp = [[[NSWorkspace sharedWorkspace] runningApplications] filteredArrayUsingPredicate:predicate];
@ -245,9 +256,9 @@
});
[self registerOrDeregisterICloudSync];
// Check if the app has Accessibility permission
[NSApp activateIgnoringOtherApps: YES];
// Check if the app has Accessibility permission
[self showAccessibilityAlert];
[self showOldOSXAlert];
}
@ -664,10 +675,22 @@
[appearancePanel addSubview:row];
nextYMax = row.frame.origin.y;
#ifdef SANDBOXING
// Hide the Save Clippings preferences. These work fine when sandboxed. They just save to somwehere under ~/Library/Containers. If SANDBOXING isn't set, automatic saving of forgotten clippings will go somewhere under ~/Library/Containers while manual saving (s or S in the bezel) will open an NSSavePanel to prompt the user to pick.
forgottenItemLabel.hidden = YES;
forgottenClippingsCheckbox.hidden = YES;
forgottenFavoritesCheckbox.hidden = YES;
savingSectionLabel.hidden = YES;
saveToLocationButton.hidden = YES;
autoSaveToLocationButton.hidden = YES;
saveFromBezelToLabel.hidden = YES;
#endif
if ([AppController isAppSandboxed]) {
// Saving to a prior-selected location while sandboxed would be unpleasant, so these really should be disabled always when sandboxed but can still show where the saves happen so the user knows what to expect.
saveToLocationButton.enabled = NO;
[saveToLocationButton setTitle:@"Ask User"];
autoSaveToLocationButton.enabled = NO;
[autoSaveToLocationButton setTitle:@"App Sandbox"];
}
}
-(IBAction) showPreferencePanel:(id)sender
@ -683,19 +706,32 @@
encoding:NSUTF8StringEncoding
error:NULL];
[acknowledgementsView setString:contents];
if (![AppController isAppSandboxed]) {
NSURL* saveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"saveToLocation"];
if (saveToLocation) {
[saveToLocationButton setTitle:[saveToLocation lastPathComponent]];
}
NSURL* autoSaveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"autoSaveToLocation"];
if (autoSaveToLocation) {
[autoSaveToLocationButton setTitle:[autoSaveToLocation lastPathComponent]];
}
}
[flycutOperator willShowPreferences];
}
-(IBAction)toggleLoadOnStartup:(id)sender {
// Since the control in Interface Builder is bound to User Defaults and sends this action, this method is called after User Defaults already reflects the newly-selected state and merely conveys that value to the relevant mechanisms rather than acting to negate the User Defaults state.
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"loadOnStartup"] ) {
// FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])"
#ifdef SANDBOXING
SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, YES);
#else
[UKLoginItemRegistry addLoginItemWithPath:[[NSBundle mainBundle] bundlePath] hideIt:NO];
#endif
} else {
// FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])"
#ifdef SANDBOXING
SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, YES);
SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, NO);
#else
[UKLoginItemRegistry removeLoginItemWithPath:[[NSBundle mainBundle] bundlePath]];
#endif
@ -857,7 +893,7 @@
if (largeCopyRisk)
[self toggleMenuIconDisabled];
if ( contents == nil || [flycutOperator shouldSkip:contents ofType:[jcPasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]] ) {
if ( contents == nil || [flycutOperator shouldSkip:contents ofType:[jcPasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] fromAvailableTypes:[jcPasteboard types]] ) {
DLog(@"Contents: Empty or skipped");
} else if ( ! [pbCount isEqualTo:pbBlockCount] ) {
[flycutOperator addClipping:contents ofType:type fromApp:[currRunningApp localizedName] withAppBundleURL:currRunningApp.bundleURL.path target:self clippingAddedSelector:@selector(updateMenu)];
@ -1177,6 +1213,37 @@ didFailToRegisterForRemoteNotificationsWithError:(NSError *)error {
}
}
- (IBAction)selectSaveLocation:(id)sender {
// Create and configure the panel.
NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel retain];
[panel setCanChooseFiles:NO];
[panel setCanChooseDirectories:YES];
[panel setCanCreateDirectories:YES];
[panel setAllowsMultipleSelection:NO];
[panel setMessage:@"Select a directory."];
// Display the panel attached to the document's window.
[panel beginSheetModalForWindow:prefsPanel completionHandler:^(NSInteger result){
if (result == NSFileHandlingPanelOKButton) {
NSURL* url = [[panel URLs] firstObject];
[panel release];
if (!url) { return; }
if (sender == saveToLocationButton) {
[[NSUserDefaults standardUserDefaults] setURL:url forKey:@"saveToLocation"];
}
else if (sender == autoSaveToLocationButton) {
[[NSUserDefaults standardUserDefaults] setURL:url forKey:@"autoSaveToLocation"];
}
[sender setTitle:[url lastPathComponent]];
}
}];
}
-(IBAction)clearClippingList:(id)sender {
int choice;

View file

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="19162" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="19162"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -97,12 +97,16 @@
<connections>
<outlet property="acknowledgementsView" destination="357" id="2y8-wF-wPX"/>
<outlet property="appearancePanel" destination="EFy-pc-aKl" id="NYD-Y7-bfQ"/>
<outlet property="autoSaveToLocationButton" destination="PJD-Fc-76A" id="UqW-Sy-cr5"/>
<outlet property="forgottenClippingsCheckbox" destination="LLh-vf-2Q3" id="JMi-Mi-Nlx"/>
<outlet property="forgottenFavoritesCheckbox" destination="cGj-g9-2Dm" id="KSf-aG-7Of"/>
<outlet property="forgottenItemLabel" destination="FNU-zj-OIm" id="xkC-K8-zNt"/>
<outlet property="jcMenu" destination="206" id="215"/>
<outlet property="mainRecorder" destination="555" id="556"/>
<outlet property="prefsPanel" destination="218" id="220"/>
<outlet property="saveFromBezelToLabel" destination="GRg-nv-Opa" id="hLw-Hb-VQg"/>
<outlet property="saveToLocationButton" destination="Bqn-So-8E9" id="vh2-7q-lE5"/>
<outlet property="savingSectionLabel" destination="g6p-DW-uAA" id="4n5-RC-Ijw"/>
<outlet property="searchBox" destination="BYk-Gn-IDB" id="MpX-C1-cdn"/>
</connections>
</customObject>
@ -111,33 +115,31 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="542" y="303" width="507" height="471"/>
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/>
<rect key="screenRect" x="0.0" y="0.0" width="1680" height="1025"/>
<value key="minSize" type="size" width="213" height="107"/>
<view key="contentView" id="219">
<rect key="frame" x="0.0" y="0.0" width="507" height="471"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="345">
<rect key="frame" x="0.0" y="0.0" width="507" height="471"/>
<rect key="frame" x="0.0" y="0.0" width="507" height="520"/>
<autoresizingMask key="autoresizingMask"/>
<font key="font" metaFont="system"/>
<tabViewItems>
<tabViewItem label="General" identifier="net.sf.jumpcut.preferences.general.tiff" id="359">
<view key="view" ambiguous="YES" id="360">
<rect key="frame" x="0.0" y="0.0" width="507" height="471"/>
<view key="view" id="360">
<rect key="frame" x="0.0" y="0.0" width="507" height="520"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<box fixedFrame="YES" boxType="oldStyle" borderType="none" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="387">
<rect key="frame" x="-3" y="136" width="555" height="349"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" ambiguous="YES" id="OKE-OW-DrT">
<rect key="frame" x="0.0" y="0.0" width="555" height="349"/>
<box misplaced="YES" boxType="oldStyle" borderType="none" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="387">
<rect key="frame" x="0.0" y="40" width="507" height="520"/>
<view key="contentView" id="OKE-OW-DrT">
<rect key="frame" x="0.0" y="0.0" width="507" height="520"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button toolTip="The bezel must be manually dismissed using the &quot;escape&quot; or &quot;return&quot; keys." fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="390">
<rect key="frame" x="14" y="319" width="97" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Sticky bezel" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="750">
<button toolTip="The bezel must be manually dismissed using the &quot;escape&quot; or &quot;return&quot; keys." translatesAutoresizingMaskIntoConstraints="NO" id="390">
<rect key="frame" x="14" y="487" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Sticky bezel (bezel, or pop-up, stays visible after hotkey is released)" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="750">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
@ -145,12 +147,93 @@
<binding destination="808" name="value" keyPath="values.stickyBezel" id="811"/>
</connections>
</button>
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="392">
<rect key="frame" x="79" y="179" width="189" height="26"/>
<autoresizingMask key="autoresizingMask"/>
<button toolTip="In the bezel, moving down from the last item takes you to the top and moving up from the first item takes you to the bottom." translatesAutoresizingMaskIntoConstraints="NO" id="692">
<rect key="frame" x="14" y="467" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Wraparound bezel (the first and last items are adjacent in order)" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="762">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.wraparoundBezel" id="814"/>
</connections>
</button>
<button toolTip="Selecting a clipping from the menu causes it to be pasted instead of copied back onto the pasteboard." translatesAutoresizingMaskIntoConstraints="NO" id="694">
<rect key="frame" x="14" y="447" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Menu selection pastes" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="763">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.menuSelectionPastes" id="817"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="398">
<rect key="frame" x="14" y="427" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Launch Flycut on login" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="753">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleLoadOnStartup:" target="213" id="773"/>
<binding destination="808" name="value" keyPath="values.loadOnStartup" id="820"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oXn-B4-1Ni">
<rect key="frame" x="34" y="408" width="80" height="16"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="iCloud Sync:" id="17g-S0-Mqp">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button translatesAutoresizingMaskIntoConstraints="NO" id="bqG-v4-vqw">
<rect key="frame" x="118" y="407" width="77" height="18"/>
<buttonCell key="cell" type="check" title="Settings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="d4T-QV-zqa">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleICloudSyncSettings:" target="213" id="lWN-Hi-1aI"/>
<binding destination="808" name="value" keyPath="values.syncSettingsViaICloud" id="q7Y-Id-atI"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="IXN-q7-y5J">
<rect key="frame" x="201" y="407" width="83" height="18"/>
<buttonCell key="cell" type="check" title="Clippings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="oLL-dD-GRW">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleICloudSyncClippings:" target="213" id="hdD-v4-8dV"/>
<binding destination="808" name="value" keyPath="values.syncClippingsViaICloud" id="gbJ-fW-npv"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="416">
<rect key="frame" x="14" y="384" width="479" height="16"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Clippings:" id="754">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="1000" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="418">
<rect key="frame" x="14" y="348" width="30" height="28"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="755">
<font key="font" metaFont="label" size="11"/>
<string key="title">Save
</string>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<popUpButton verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="392">
<rect key="frame" x="47" y="355" width="189" height="25"/>
<constraints>
<constraint firstAttribute="width" constant="182" id="xgu-QS-ucU"/>
</constraints>
<popUpButtonCell key="cell" type="push" title="On exit" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="394" id="751">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
<font key="font" metaFont="menu"/>
<menu key="menu" title="OtherViews" id="393">
<items>
<menuItem title="Never" id="395"/>
@ -164,86 +247,8 @@
<binding destination="808" name="selectedIndex" keyPath="values.savePreference" id="823"/>
</connections>
</popUpButton>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="398">
<rect key="frame" x="14" y="259" width="162" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Launch Flycut on login" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="753">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleLoadOnStartup:" target="213" id="773"/>
<binding destination="808" name="value" keyPath="values.loadOnStartup" id="820"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IXN-q7-y5J">
<rect key="frame" x="193" y="239" width="79" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Clippings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="oLL-dD-GRW">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleICloudSyncClippings:" target="213" id="hdD-v4-8dV"/>
<binding destination="808" name="value" keyPath="values.syncClippingsViaICloud" id="gbJ-fW-npv"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="897">
<rect key="frame" x="14" y="123" width="247" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Don't copy from password fields" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="898">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordFields" id="902"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="903">
<rect key="frame" x="14" y="41" width="247" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Remove duplicates" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="904">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.removeDuplicates" id="906"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="416">
<rect key="frame" x="13" y="207" width="76" height="23"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="754">
<font key="font" metaFont="system"/>
<string key="title">Clippings:
</string>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="oXn-B4-1Ni">
<rect key="frame" x="32" y="223" width="116" height="34"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="iCloud Sync:" id="17g-S0-Mqp">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="418">
<rect key="frame" x="13" y="185" width="33" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="755">
<font key="font" metaFont="label" size="11"/>
<string key="title">Save
</string>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="419">
<rect key="frame" x="13" y="159" width="62" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="419">
<rect key="frame" x="14" y="312" width="61" height="28"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="756">
<font key="font" metaFont="label" size="11"/>
<string key="title">Remember
@ -252,19 +257,12 @@
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="420">
<rect key="frame" x="134" y="159" width="95" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Display in menu" id="757">
<font key="font" metaFont="label" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="470">
<rect key="frame" x="79" y="154" width="25" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" id="758">
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="470">
<rect key="frame" x="79" y="326" width="34" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="CUk-dH-iV9"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" alignment="right" placeholderString="000" id="758">
<numberFormatter key="formatter" formatterBehavior="10_0" positiveFormat="#" negativeFormat="-#" hasThousandSeparators="NO" thousandSeparator=" " id="483">
<attributedString key="attributedStringForZero">
<fragment content="0"/>
@ -280,10 +278,28 @@
<binding destination="808" name="value" keyPath="values.rememberNum" id="826"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="471">
<rect key="frame" x="224" y="154" width="24" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" id="759">
<stepper toolTip="Controls how many clippings Flycut stores in its stack" horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="472">
<rect key="frame" x="113" y="320" width="19" height="28"/>
<stepperCell key="cell" continuous="YES" alignment="left" minValue="10" maxValue="999" doubleValue="10" valueWraps="YES" id="760"/>
<connections>
<action selector="setRememberNumPref:" target="213" id="485"/>
<binding destination="808" name="value" keyPath="values.rememberNum" id="829"/>
</connections>
</stepper>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="420">
<rect key="frame" x="143" y="326" width="87" height="14"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Display in menu" id="757">
<font key="font" metaFont="label" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="471">
<rect key="frame" x="234" y="326" width="29" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="xtz-2M-8Nx"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" alignment="right" placeholderString="000" id="759">
<numberFormatter key="formatter" formatterBehavior="10_0" positiveFormat="#" negativeFormat="-#" hasThousandSeparators="NO" thousandSeparator=" " id="484">
<attributedString key="attributedStringForZero">
<fragment content="0"/>
@ -299,18 +315,8 @@
<binding destination="808" name="value" keyPath="values.displayNum" id="832"/>
</connections>
</textField>
<stepper toolTip="Controls how many clippings Flycut stores in its stack" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="472">
<rect key="frame" x="104" y="152" width="19" height="27"/>
<autoresizingMask key="autoresizingMask"/>
<stepperCell key="cell" continuous="YES" alignment="left" minValue="10" maxValue="99" doubleValue="10" valueWraps="YES" id="760"/>
<connections>
<action selector="setRememberNumPref:" target="213" id="485"/>
<binding destination="808" name="value" keyPath="values.rememberNum" id="829"/>
</connections>
</stepper>
<stepper toolTip="Controls how many clippings Flycut shows in the menu" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="473">
<rect key="frame" x="249" y="152" width="19" height="27"/>
<autoresizingMask key="autoresizingMask"/>
<stepper toolTip="Controls how many clippings Flycut shows in the menu" horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="473">
<rect key="frame" x="264" y="320" width="19" height="28"/>
<stepperCell key="cell" continuous="YES" alignment="left" minValue="5" maxValue="99" doubleValue="5" valueWraps="YES" id="761"/>
<connections>
<action selector="setDisplayNumPref:" target="213" id="486"/>
@ -318,63 +324,20 @@
<binding destination="808" name="maxValue" keyPath="values.rememberNum" id="852"/>
</connections>
</stepper>
<button toolTip="In the bezel, moving down from the last item takes you to the top and moving up from the first item takes you to the bottom." fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="692">
<rect key="frame" x="14" y="299" width="162" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Wraparound bezel" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="762">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.wraparoundBezel" id="814"/>
</connections>
</button>
<button toolTip="Selecting a clipping from the menu causes it to be pasted instead of copied back onto the pasteboard." fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="694">
<rect key="frame" x="14" y="279" width="162" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Menu selection pastes" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="763">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.menuSelectionPastes" id="817"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="914">
<rect key="frame" x="14" y="21" width="230" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Move pasted item to top of stack" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="915">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.pasteMovesToTop" id="922"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="LLh-vf-2Q3">
<rect key="frame" x="246" y="1" width="87" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Clippings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="oLu-XL-Wuo">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.saveForgottenClippings" id="9eO-xd-ge5"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ubt-DS-zHf">
<rect key="frame" x="280" y="159" width="62" height="14"/>
<autoresizingMask key="autoresizingMask"/>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ubt-DS-zHf">
<rect key="frame" x="294" y="326" width="52" height="14"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Favorites" id="2L6-OM-5rx">
<font key="font" metaFont="label" size="11"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dM5-eN-Zvt">
<rect key="frame" x="346" y="154" width="25" height="22"/>
<autoresizingMask key="autoresizingMask"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" id="nes-6O-e5R">
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dM5-eN-Zvt">
<rect key="frame" x="350" y="326" width="29" height="16"/>
<constraints>
<constraint firstAttribute="width" constant="25" id="wV6-2I-Qfq"/>
</constraints>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" state="on" alignment="right" placeholderString="000" id="nes-6O-e5R">
<numberFormatter key="formatter" formatterBehavior="10_0" positiveFormat="#" negativeFormat="-#" hasThousandSeparators="NO" thousandSeparator="," id="aqt-p2-eya">
<attributedString key="attributedStringForZero">
<fragment content="0"/>
@ -387,21 +350,37 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="808" name="value" keyPath="values.rememberNum" id="887-jS-Kpn"/>
<binding destination="808" name="value" keyPath="values.favoritesRememberNum" id="bQe-4R-RSr"/>
</connections>
</textField>
<stepper toolTip="Controls how many clippings Flycut stores in its stack" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="wZv-HJ-VdW">
<rect key="frame" x="371" y="152" width="19" height="27"/>
<autoresizingMask key="autoresizingMask"/>
<stepperCell key="cell" continuous="YES" alignment="left" minValue="10" maxValue="99" doubleValue="10" valueWraps="YES" id="gUi-gl-RH6"/>
<stepper toolTip="Controls how many clippings Flycut stores in its favorites stack" horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="wZv-HJ-VdW">
<rect key="frame" x="380" y="320" width="19" height="28"/>
<stepperCell key="cell" continuous="YES" alignment="left" minValue="10" maxValue="999" doubleValue="10" valueWraps="YES" id="gUi-gl-RH6"/>
<connections>
<action selector="setFavoritesRememberNumPref:" target="213" id="rm7-TX-1af"/>
<binding destination="808" name="value" keyPath="values.rememberNum" id="nUm-81-DgP"/>
<binding destination="808" name="value" keyPath="values.favoritesRememberNum" id="nUm-81-DgP"/>
</connections>
</stepper>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="pDS-jE-9jb">
<rect key="frame" x="32" y="103" width="133" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="IZZ-Ep-7nD" userLabel="Passwords:">
<rect key="frame" x="14" y="288" width="479" height="16"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Passwords:" id="cLX-o3-ZMz">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button translatesAutoresizingMaskIntoConstraints="NO" id="897">
<rect key="frame" x="14" y="263" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Don't copy from password fields" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="898">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordFields" id="902"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="pDS-jE-9jb">
<rect key="frame" x="34" y="243" width="136" height="18"/>
<buttonCell key="cell" type="check" title="Pasteboard types:" bezelStyle="regularSquare" imagePosition="left" inset="2" id="tzh-NM-RSb">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -410,43 +389,8 @@
<binding destination="808" name="value" keyPath="values.skipPboardTypes" id="kfD-fG-t1V"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Bxp-pI-XMk">
<rect key="frame" x="32" y="82" width="356" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Detect with Upper, Lower, Digit, and Symbol lengths:" bezelStyle="regularSquare" imagePosition="left" inset="2" id="aAK-L0-EHa">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordLengths" id="PyJ-gO-ieM"/>
</connections>
</button>
<button toolTip="For identifying types to include in Pasteboard Types above." fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mka-NZ-Esg">
<rect key="frame" x="32" y="62" width="279" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Include pasteboard types in clippings list" bezelStyle="regularSquare" imagePosition="left" inset="2" id="9Vi-RY-G0b">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.revealPasteboardTypes" id="Nn3-7D-D7e"/>
</connections>
</button>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RYj-wx-tTx">
<rect key="frame" x="394" y="80" width="108" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="12, 20, 32" drawsBackground="YES" id="aqQ-SR-BmT">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordLengthsList" id="NJg-wN-gsn"/>
</connections>
</textField>
<textField verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="x34-dK-wxl">
<rect key="frame" x="171" y="101" width="331" height="22"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="x34-dK-wxl">
<rect key="frame" x="178" y="242" width="313" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="PasswordPboardType" drawsBackground="YES" id="kTZ-dC-s1q">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
@ -456,18 +400,121 @@
<binding destination="808" name="value" keyPath="values.skipPboardTypesList" id="Wbn-u9-3vY"/>
</connections>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FNU-zj-OIm">
<rect key="frame" x="32" y="2" width="211" height="17"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Save forgotten items to Desktop:" id="ksy-al-FbE">
<button translatesAutoresizingMaskIntoConstraints="NO" id="Bxp-pI-XMk">
<rect key="frame" x="34" y="223" width="345" height="18"/>
<buttonCell key="cell" type="check" title="Detect with Upper, Lower, Digit, and Symbol lengths:" bezelStyle="regularSquare" imagePosition="left" inset="2" id="aAK-L0-EHa">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordLengths" id="PyJ-gO-ieM"/>
</connections>
</button>
<textField verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RYj-wx-tTx">
<rect key="frame" x="387" y="222" width="104" height="21"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" title="12, 20, 32" drawsBackground="YES" id="aqQ-SR-BmT">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
<connections>
<binding destination="808" name="value" keyPath="values.skipPasswordLengthsList" id="NJg-wN-gsn"/>
</connections>
</textField>
<button toolTip="For identifying types to include in Pasteboard Types above." translatesAutoresizingMaskIntoConstraints="NO" id="mka-NZ-Esg">
<rect key="frame" x="34" y="203" width="274" height="18"/>
<buttonCell key="cell" type="check" title="Include pasteboard types in clippings list" bezelStyle="regularSquare" imagePosition="left" inset="2" id="9Vi-RY-G0b">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.revealPasteboardTypes" id="Nn3-7D-D7e"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Y84-Ix-WCR" userLabel="Organizing:">
<rect key="frame" x="14" y="180" width="479" height="16"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Organizing:" id="3tC-1z-0C9">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button translatesAutoresizingMaskIntoConstraints="NO" id="903">
<rect key="frame" x="14" y="155" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Remove duplicates" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="904">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.removeDuplicates" id="906"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="914">
<rect key="frame" x="14" y="135" width="477" height="18"/>
<buttonCell key="cell" type="check" title="Move pasted item to top of stack" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="915">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.pasteMovesToTop" id="922"/>
</connections>
</button>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g6p-DW-uAA" userLabel="Saving:">
<rect key="frame" x="14" y="112" width="479" height="16"/>
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Saving:" id="bsj-XZ-XVF">
<font key="font" metaFont="systemSemibold" size="13"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="GRg-nv-Opa" userLabel="Save from bezel to:">
<rect key="frame" x="14" y="88" width="121" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Save from bezel to:" id="5L1-9C-Fdd">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="cGj-g9-2Dm">
<rect key="frame" x="337" y="1" width="157" height="18"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="Bqn-So-8E9" userLabel="SaveToButton">
<rect key="frame" x="134" y="79" width="85" height="32"/>
<buttonCell key="cell" type="push" title="Desktop" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Ldc-9D-vz1">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="selectSaveLocation:" target="213" id="wgc-Dj-9ke"/>
</connections>
</button>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="FNU-zj-OIm">
<rect key="frame" x="14" y="64" width="149" height="16"/>
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Save forgotten items to:" id="ksy-al-FbE">
<font key="font" metaFont="system"/>
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<button verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" translatesAutoresizingMaskIntoConstraints="NO" id="PJD-Fc-76A" userLabel="AutoSaveToButton">
<rect key="frame" x="162" y="55" width="85" height="32"/>
<buttonCell key="cell" type="push" title="Desktop" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="K2A-qx-BB8">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="selectSaveLocation:" target="213" id="T8h-Ac-NLL"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="LLh-vf-2Q3">
<rect key="frame" x="246" y="63" width="83" height="18"/>
<buttonCell key="cell" type="check" title="Clippings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="oLu-XL-Wuo">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="808" name="value" keyPath="values.saveForgottenClippings" id="9eO-xd-ge5"/>
</connections>
</button>
<button translatesAutoresizingMaskIntoConstraints="NO" id="cGj-g9-2Dm">
<rect key="frame" x="335" y="63" width="81" height="18"/>
<buttonCell key="cell" type="check" title="Favorites" bezelStyle="regularSquare" imagePosition="left" alignment="left" state="on" inset="2" id="vC2-Ch-UPQ">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
@ -476,33 +523,120 @@
<binding destination="808" name="value" keyPath="values.saveForgottenFavorites" id="WTf-Ip-R9L"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bqG-v4-vqw">
<rect key="frame" x="116" y="239" width="73" height="18"/>
<autoresizingMask key="autoresizingMask"/>
<buttonCell key="cell" type="check" title="Settings" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="d4T-QV-zqa">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="toggleICloudSyncSettings:" target="213" id="lWN-Hi-1aI"/>
<binding destination="808" name="value" keyPath="values.syncSettingsViaICloud" id="q7Y-Id-atI"/>
</connections>
</button>
</subviews>
<constraints>
<constraint firstItem="419" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="0OA-ei-ed9"/>
<constraint firstItem="IZZ-Ep-7nD" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="1Yq-Ci-o9Y"/>
<constraint firstItem="897" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="2EU-FY-QhB"/>
<constraint firstItem="470" firstAttribute="leading" secondItem="419" secondAttribute="trailing" constant="8" symbolic="YES" id="2SS-tf-dnl"/>
<constraint firstItem="x34-dK-wxl" firstAttribute="leading" secondItem="pDS-jE-9jb" secondAttribute="trailing" constant="8" id="2oa-Ko-tPw"/>
<constraint firstItem="390" firstAttribute="top" secondItem="OKE-OW-DrT" secondAttribute="top" constant="16" id="3WW-PL-oMV"/>
<constraint firstItem="390" firstAttribute="leading" secondItem="OKE-OW-DrT" secondAttribute="leading" constant="16" id="4AU-hf-tHV"/>
<constraint firstItem="Bqn-So-8E9" firstAttribute="leading" secondItem="GRg-nv-Opa" secondAttribute="trailing" constant="8" id="4Yw-Fu-mY5"/>
<constraint firstItem="IZZ-Ep-7nD" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="58a-TR-ref"/>
<constraint firstItem="x34-dK-wxl" firstAttribute="centerY" secondItem="pDS-jE-9jb" secondAttribute="centerY" id="5gD-Jm-AWK"/>
<constraint firstAttribute="trailing" secondItem="x34-dK-wxl" secondAttribute="trailing" constant="16" id="63n-I3-kLa"/>
<constraint firstItem="GRg-nv-Opa" firstAttribute="top" secondItem="g6p-DW-uAA" secondAttribute="bottom" constant="8" id="63n-kR-a6q"/>
<constraint firstItem="903" firstAttribute="top" secondItem="Y84-Ix-WCR" secondAttribute="bottom" constant="8" id="85d-e5-tMQ"/>
<constraint firstItem="419" firstAttribute="top" secondItem="418" secondAttribute="bottom" constant="8" id="8QQ-I9-aMj"/>
<constraint firstItem="Y84-Ix-WCR" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="8n3-Fh-HPU"/>
<constraint firstItem="470" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="9I5-Oh-rPd"/>
<constraint firstItem="Bqn-So-8E9" firstAttribute="centerY" secondItem="GRg-nv-Opa" secondAttribute="centerY" id="AFQ-dB-abo"/>
<constraint firstItem="398" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="BAI-dH-bSv"/>
<constraint firstAttribute="bottom" relation="greaterThanOrEqual" secondItem="FNU-zj-OIm" secondAttribute="bottom" constant="16" id="Bgo-q3-Evl"/>
<constraint firstItem="416" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="BxJ-J8-n2m"/>
<constraint firstAttribute="trailing" secondItem="RYj-wx-tTx" secondAttribute="trailing" constant="16" id="C8f-Q9-F5O"/>
<constraint firstItem="903" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="CEg-IE-Ros"/>
<constraint firstItem="dM5-eN-Zvt" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="CW3-B2-Nke"/>
<constraint firstItem="416" firstAttribute="top" secondItem="oXn-B4-1Ni" secondAttribute="bottom" constant="8" id="F4X-cP-nBC"/>
<constraint firstItem="FNU-zj-OIm" firstAttribute="centerY" secondItem="PJD-Fc-76A" secondAttribute="centerY" id="GLR-pi-A9f"/>
<constraint firstItem="pDS-jE-9jb" firstAttribute="leading" secondItem="897" secondAttribute="leading" constant="20" id="GYo-j6-3vw"/>
<constraint firstItem="398" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="Ggu-1n-f2v"/>
<constraint firstItem="914" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="HgF-tD-X6T"/>
<constraint firstItem="Bxp-pI-XMk" firstAttribute="top" secondItem="pDS-jE-9jb" secondAttribute="bottom" constant="4" id="IB8-Wb-AWb"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="cGj-g9-2Dm" secondAttribute="trailing" constant="16" id="IO6-sz-Wmo"/>
<constraint firstItem="mka-NZ-Esg" firstAttribute="top" secondItem="Bxp-pI-XMk" secondAttribute="bottom" constant="4" id="LMp-eg-a6v"/>
<constraint firstItem="398" firstAttribute="top" secondItem="694" secondAttribute="bottom" constant="4" id="LYa-Bc-sCv"/>
<constraint firstItem="oXn-B4-1Ni" firstAttribute="leading" secondItem="398" secondAttribute="leading" constant="20" id="LiX-K9-GGv"/>
<constraint firstItem="694" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="MBb-5l-ePl"/>
<constraint firstItem="dM5-eN-Zvt" firstAttribute="leading" secondItem="Ubt-DS-zHf" secondAttribute="trailing" constant="8" symbolic="YES" id="NXg-qx-3RD"/>
<constraint firstItem="392" firstAttribute="firstBaseline" secondItem="418" secondAttribute="firstBaseline" id="NYT-Ws-Grq"/>
<constraint firstItem="LLh-vf-2Q3" firstAttribute="centerY" secondItem="FNU-zj-OIm" secondAttribute="centerY" id="OCy-GX-PhU"/>
<constraint firstItem="897" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="OOV-o3-Kqw"/>
<constraint firstItem="IXN-q7-y5J" firstAttribute="leading" secondItem="bqG-v4-vqw" secondAttribute="trailing" constant="8" id="OWr-XG-nOi"/>
<constraint firstItem="cGj-g9-2Dm" firstAttribute="leading" secondItem="LLh-vf-2Q3" secondAttribute="trailing" constant="8" id="OiD-MJ-3oZ"/>
<constraint firstItem="bqG-v4-vqw" firstAttribute="leading" secondItem="oXn-B4-1Ni" secondAttribute="trailing" constant="8" id="Pnm-sg-o01"/>
<constraint firstItem="PJD-Fc-76A" firstAttribute="leading" secondItem="FNU-zj-OIm" secondAttribute="trailing" constant="8" id="QQj-Rc-WHS"/>
<constraint firstItem="694" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="QjU-Yy-d2y"/>
<constraint firstItem="cGj-g9-2Dm" firstAttribute="centerY" secondItem="FNU-zj-OIm" secondAttribute="centerY" id="UXg-nV-5uk"/>
<constraint firstItem="418" firstAttribute="top" secondItem="416" secondAttribute="bottom" constant="8" id="VNz-aL-KCx"/>
<constraint firstItem="473" firstAttribute="leading" secondItem="471" secondAttribute="trailing" constant="6" id="VdT-8E-s3R"/>
<constraint firstItem="Bqn-So-8E9" firstAttribute="trailing" relation="lessThanOrEqual" secondItem="390" secondAttribute="trailing" id="VeU-DE-gRe"/>
<constraint firstItem="Y84-Ix-WCR" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="WHB-9p-hWJ"/>
<constraint firstItem="wZv-HJ-VdW" firstAttribute="leading" secondItem="dM5-eN-Zvt" secondAttribute="trailing" constant="6" id="WrE-NL-zxb"/>
<constraint firstItem="420" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="X0m-LH-JXU"/>
<constraint firstItem="Bxp-pI-XMk" firstAttribute="leading" secondItem="897" secondAttribute="leading" constant="20" id="XCO-Pl-Mxm"/>
<constraint firstItem="471" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="XmO-SK-wbg"/>
<constraint firstItem="LLh-vf-2Q3" firstAttribute="leading" secondItem="PJD-Fc-76A" secondAttribute="trailing" constant="8" id="ZkB-0I-uW3"/>
<constraint firstItem="g6p-DW-uAA" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="aJn-m2-qIb"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="wZv-HJ-VdW" secondAttribute="trailing" constant="16" id="bAa-Y7-Ufp"/>
<constraint firstItem="897" firstAttribute="top" secondItem="IZZ-Ep-7nD" secondAttribute="bottom" constant="8" id="bWw-xW-3pk"/>
<constraint firstItem="Ubt-DS-zHf" firstAttribute="leading" secondItem="473" secondAttribute="trailing" constant="16" id="bq9-zJ-hAm"/>
<constraint firstItem="pDS-jE-9jb" firstAttribute="top" secondItem="897" secondAttribute="bottom" constant="4" id="bzC-5n-599"/>
<constraint firstItem="g6p-DW-uAA" firstAttribute="top" secondItem="914" secondAttribute="bottom" constant="8" id="c0s-2l-T8Z"/>
<constraint firstItem="GRg-nv-Opa" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="cgO-SI-hPU"/>
<constraint firstItem="wZv-HJ-VdW" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="crp-Nh-USz"/>
<constraint firstItem="914" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="dnB-pc-kVq"/>
<constraint firstItem="471" firstAttribute="leading" secondItem="420" secondAttribute="trailing" constant="8" symbolic="YES" id="dpK-2h-xHg"/>
<constraint firstItem="Ubt-DS-zHf" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="ea2-3T-gv7"/>
<constraint firstItem="472" firstAttribute="leading" secondItem="470" secondAttribute="trailing" constant="5" id="em0-Uc-eQr"/>
<constraint firstItem="418" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="gzd-Qn-vkn"/>
<constraint firstItem="420" firstAttribute="leading" secondItem="472" secondAttribute="trailing" constant="16" id="ish-En-B66"/>
<constraint firstItem="692" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="jLX-6E-xU8"/>
<constraint firstItem="IXN-q7-y5J" firstAttribute="centerY" secondItem="oXn-B4-1Ni" secondAttribute="centerY" id="jrR-OL-dfq"/>
<constraint firstItem="472" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="k8D-eK-Lkg"/>
<constraint firstItem="mka-NZ-Esg" firstAttribute="leading" secondItem="897" secondAttribute="leading" constant="20" id="kqa-hO-Tgb"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="IXN-q7-y5J" secondAttribute="trailing" constant="16" id="lnR-NY-f9w"/>
<constraint firstItem="903" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="mcA-EQ-hXJ"/>
<constraint firstItem="692" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="nT0-7c-Qau"/>
<constraint firstItem="FNU-zj-OIm" firstAttribute="top" secondItem="GRg-nv-Opa" secondAttribute="bottom" constant="8" id="p6b-hb-TkQ"/>
<constraint firstItem="392" firstAttribute="leading" secondItem="418" secondAttribute="trailing" constant="8" id="qNy-dd-GTI"/>
<constraint firstItem="694" firstAttribute="top" secondItem="692" secondAttribute="bottom" constant="4" id="qVT-TM-MxF"/>
<constraint firstItem="Y84-Ix-WCR" firstAttribute="top" secondItem="mka-NZ-Esg" secondAttribute="bottom" constant="8" id="qcI-Ml-osE"/>
<constraint firstItem="oXn-B4-1Ni" firstAttribute="top" secondItem="398" secondAttribute="bottom" constant="4" id="rLY-8f-Ddg"/>
<constraint firstItem="RYj-wx-tTx" firstAttribute="centerY" secondItem="Bxp-pI-XMk" secondAttribute="centerY" id="t66-fT-3SX"/>
<constraint firstAttribute="trailing" secondItem="390" secondAttribute="trailing" constant="16" id="ti1-k0-aLE"/>
<constraint firstItem="RYj-wx-tTx" firstAttribute="leading" secondItem="Bxp-pI-XMk" secondAttribute="trailing" constant="8" id="uer-Iu-d76"/>
<constraint firstItem="g6p-DW-uAA" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="v9C-kf-Qoy"/>
<constraint firstItem="416" firstAttribute="trailing" secondItem="390" secondAttribute="trailing" id="vN9-3Q-dlX"/>
<constraint firstItem="914" firstAttribute="top" secondItem="903" secondAttribute="bottom" constant="4" id="vUJ-m6-h6j"/>
<constraint firstAttribute="trailing" relation="greaterThanOrEqual" secondItem="392" secondAttribute="trailing" constant="16" id="w0m-0A-rhs"/>
<constraint firstItem="bqG-v4-vqw" firstAttribute="centerY" secondItem="oXn-B4-1Ni" secondAttribute="centerY" id="xqP-UF-xeE"/>
<constraint firstItem="473" firstAttribute="firstBaseline" secondItem="419" secondAttribute="firstBaseline" id="yKX-vf-1GN"/>
<constraint firstItem="FNU-zj-OIm" firstAttribute="leading" secondItem="390" secondAttribute="leading" id="yqk-DD-uql"/>
<constraint firstItem="692" firstAttribute="top" secondItem="390" secondAttribute="bottom" constant="4" id="yvi-Jb-7If"/>
<constraint firstItem="IZZ-Ep-7nD" firstAttribute="top" secondItem="419" secondAttribute="bottom" constant="8" id="ztE-db-uZr"/>
</constraints>
</view>
</box>
</subviews>
<constraints>
<constraint firstAttribute="trailing" secondItem="387" secondAttribute="trailing" id="1tp-B7-zu0"/>
<constraint firstItem="387" firstAttribute="top" secondItem="360" secondAttribute="top" id="nuT-kv-kuD"/>
<constraint firstItem="387" firstAttribute="leading" secondItem="360" secondAttribute="leading" id="zUp-0A-XJv"/>
<constraint firstAttribute="bottom" secondItem="387" secondAttribute="bottom" id="zmW-H9-0um"/>
</constraints>
</view>
</tabViewItem>
<tabViewItem label="Hotkeys" identifier="net.sf.jumpcut.preferences.hotkey.tiff" id="346">
<view key="view" id="347">
<rect key="frame" x="0.0" y="0.0" width="507" height="471"/>
<rect key="frame" x="0.0" y="0.0" width="507" height="520"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<box fixedFrame="YES" boxType="oldStyle" borderType="none" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="348">
<rect key="frame" x="0.0" y="227" width="555" height="125"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" ambiguous="YES" id="Kdy-dK-U26">
<view key="contentView" id="Kdy-dK-U26">
<rect key="frame" x="0.0" y="0.0" width="555" height="125"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
@ -564,18 +698,18 @@
<box fixedFrame="YES" boxType="oldStyle" borderType="none" title="Box" titlePosition="noTitle" translatesAutoresizingMaskIntoConstraints="NO" id="354">
<rect key="frame" x="-3" y="109" width="555" height="376"/>
<autoresizingMask key="autoresizingMask"/>
<view key="contentView" ambiguous="YES" id="Rzy-Jv-79m">
<view key="contentView" id="Rzy-Jv-79m">
<rect key="frame" x="0.0" y="0.0" width="555" height="376"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView fixedFrame="YES" horizontalLineScroll="0.0" horizontalPageScroll="0.0" verticalLineScroll="0.0" verticalPageScroll="0.0" hasHorizontalScroller="NO" hasVerticalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="356">
<rect key="frame" x="16" y="16" width="476" height="346"/>
<autoresizingMask key="autoresizingMask"/>
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" id="Yuw-af-7PF">
<clipView key="contentView" drawsBackground="NO" id="Yuw-af-7PF">
<rect key="frame" x="1" y="1" width="474" height="344"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<textView ambiguous="YES" editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" usesFontPanel="YES" usesRuler="YES" spellingCorrection="YES" smartInsertDelete="YES" id="357">
<textView editable="NO" importsGraphics="NO" richText="NO" verticallyResizable="YES" usesFontPanel="YES" usesRuler="YES" spellingCorrection="YES" smartInsertDelete="YES" id="357">
<rect key="frame" x="0.0" y="0.0" width="474" height="344"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="textColor" name="textColor" catalog="System" colorSpace="catalog"/>
@ -586,7 +720,7 @@
<fragment content="This text is loaded from acknowledgements.txt">
<attributes>
<color key="NSColor" name="textColor" catalog="System" colorSpace="catalog"/>
<font key="NSFont" metaFont="user"/>
<font key="NSFont" usesAppearanceFont="YES"/>
<paragraphStyle key="NSParagraphStyle" alignment="natural" lineBreakMode="wordWrapping" baseWritingDirection="natural"/>
</attributes>
</fragment>
@ -640,7 +774,7 @@
</connections>
</searchField>
</subviews>
<point key="canvasLocation" x="194" y="396"/>
<point key="canvasLocation" x="457" y="209"/>
</customView>
</objects>
</document>

Binary file not shown.

Binary file not shown.

View file

@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
if #available(iOS 10.0, *) {
let center = UNUserNotificationCenter.current()

View file

@ -15,7 +15,7 @@ class SettingsViewController: IASKAppSettingsViewController {
}
// - (id)initWithStyle:(UITableViewStyle)style {
required override init(style:UITableViewStyle) {
required override init(style:UITableView.Style) {
super.init(style: style)
commonInitContent()
}

View file

@ -13,7 +13,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
let flycut:FlycutOperator = FlycutOperator()
var activeUpdates:Int = 0
var tableView:UITableView!
var currentAnimation = UITableViewRowAnimation.none
var currentAnimation = UITableView.RowAnimation.none
var pbCount:Int = -1
var rememberedSyncSettings:Bool = false
var rememberedSyncClippings:Bool = false
@ -60,7 +60,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
let indexPath = self.tableView.indexPath(for: cell)
if ( nil != indexPath ) {
let previousAnimation = self.currentAnimation
self.currentAnimation = UITableViewRowAnimation.left // Use .left to look better with swiping left to delete.
self.currentAnimation = UITableView.RowAnimation.left // Use .left to look better with swiping left to delete.
self.flycut.setStackPositionTo( Int32((indexPath?.row)! ))
self.flycut.clearItemAtStackPosition()
self.currentAnimation = previousAnimation
@ -79,7 +79,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
// Fallback on earlier versions
UIApplication.shared.openURL(url!)
}
self.tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none)
self.tableView.reloadRows(at: [indexPath!], with: UITableView.RowAnimation.none)
}
return true;
@ -100,18 +100,18 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
flycut.awake(fromNibDisplaying: 10, withDisplayLength: 140, withSave: #selector(savePreferences(toDict:)), forTarget: self) // The 10 isn't used in iOS right now and 140 characters seems to be enough to cover the width of the largest screen.
NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: .UIPasteboardChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: UIPasteboard.changedNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.applicationWillTerminate), name: .UIApplicationWillTerminate, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.applicationWillTerminate), name: UIApplication.willTerminateNotification, object: nil)
// Check for clipping whenever we become active.
NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: .UIApplicationDidBecomeActive, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: UIApplication.didBecomeActiveNotification, object: nil)
checkForClippingAddedToClipboard() // Since the first-launch notification will occur before we add observer.
// Register for notifications for the scenarios in which we should save the engine.
[ Notification.Name.UIApplicationWillResignActive,
Notification.Name.UIApplicationDidEnterBackground,
Notification.Name.UIApplicationWillTerminate ]
[ UIApplication.willResignActiveNotification,
UIApplication.didEnterBackgroundNotification,
UIApplication.willTerminateNotification ]
.forEach { (notification) in
NotificationCenter.default.addObserver(self,
selector: #selector(self.saveEngine),
@ -148,7 +148,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
}
}
func defaultsChanged() {
@objc func defaultsChanged() {
// This seems to be the only way to respond to Settings changes, though it doesn't inform us what changed so we will have to check each to see if they were the one(s).
// Don't use DispatchQueue.main.async since that will still end up blocking the UI draw until the user responds to what hasn't been drawn yet.
@ -209,7 +209,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
flycut.willShowPreferences()
}
func savePreferences(toDict: NSMutableDictionary)
@objc func savePreferences(toDict: NSMutableDictionary)
{
}
@ -320,7 +320,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
return selection
}
func checkForClippingAddedToClipboard()
@objc func checkForClippingAddedToClipboard()
{
pasteboardInteractionQueue.async {
// This is a suitable place to prepare to possible eventual display of preferences, resetting values that should reset before each display of preferences.
@ -330,26 +330,26 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
{
self.pbCount = UIPasteboard.general.changeCount;
if ( UIPasteboard.general.types.contains("public.utf8-plain-text") )
if UIPasteboard.general.types.contains("public.utf8-plain-text"),
let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.utf8-plain-text") as? String
{
let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.utf8-plain-text")
self.flycut.addClipping(pasteboard as! String!, ofType: "public.utf8-plain-text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil)
self.flycut.addClipping(pasteboard, ofType: "public.utf8-plain-text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil)
}
else if ( UIPasteboard.general.types.contains("public.text") )
else if UIPasteboard.general.types.contains("public.text"),
let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.text") as? String
{
let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.text")
self.flycut.addClipping(pasteboard as! String!, ofType: "public.text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil)
self.flycut.addClipping(pasteboard, ofType: "public.text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil)
}
}
}
}
func applicationWillTerminate()
@objc func applicationWillTerminate()
{
saveEngine()
}
func saveEngine()
@objc func saveEngine()
{
flycut.saveEngine()
}
@ -371,7 +371,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let item: MGSwipeTableCell = tableView.dequeueReusableCell(withIdentifier: "FlycutCell", for: indexPath) as! MGSwipeTableCell
item.textLabel?.text = flycut.previousDisplayStrings(indexPath.row + 1, containing: nil).last as! String?
item.textLabel?.text = flycut.previousDisplayStrings(Int32(indexPath.row + 1), containing: nil).last as! String?
//configure left buttons
var removeAll:Bool = true
@ -382,7 +382,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
// NSTextCheckingResult.CheckingType.link.rawValue blocks things like single words that URL() would let in
// URL() blocks things like paragraphs of text containing a URL that NSTextCheckingResult.CheckingType.link.rawValue would let in
let matches = isURLDetector?.matches(in: content, options: .reportCompletion, range: NSMakeRange(0, content.characters.count))
let matches = isURLDetector?.matches(in: content, options: .reportCompletion, range: NSMakeRange(0, content.count))
if let matchesCount = matches?.count
{
if matchesCount > 0
@ -445,8 +445,9 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour
}
func notifyCKAccountStatusNoAccount() {
if ( !ignoreCKAccountStatusNoAccount )
{
DispatchQueue.main.async {
guard !self.ignoreCKAccountStatusNoAccount else { return }
let alert = UIAlertController(title: "No iCloud Account", message: "An iCloud account with iCloud Drive enabled is required for iCloud sync.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Preferences", style: .default, handler: { (_) in
if #available(iOS 10.0, *)

View file

@ -4,6 +4,8 @@
#ifdef __OBJC__
#define kiCloudId @"iCloud.com.mark-a-jerde.Flycut"
#ifdef DEBUG
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else

View file

@ -14,5 +14,7 @@
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

View file

@ -779,6 +779,7 @@
8D1107290486CEB800E47090 /* Resources */,
8D11072C0486CEB800E47090 /* Sources */,
8D11072E0486CEB800E47090 /* Frameworks */,
8D60A1BA1BC8399900A26CBF /* Set meaningful build number */,
AAE2036C0A27B2B9002DCC2A /* Headers */,
77AE730823D2D49100F6A44B /* Embed Frameworks */,
77192A3923D6F45F00EDB9BC /* CopyFiles */,
@ -1013,6 +1014,24 @@
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
8D60A1BA1BC8399900A26CBF /* Set meaningful build number */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 12;
files = (
);
inputPaths = (
$BUILT_PRODUCTS_DIR/$INFOPLIST_PATH,
);
name = "Set meaningful build number";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Sets the build number to identify, to some extent, the git version of the code.\n# Combines the hash of the origin commit, number of commits of divergence, local HEAD commit, local uncommitted lines of change, and year/month of build.\n# Eliminates all except for the origin commit if there are no local changes, since that can be easily tracked.\n# e.g. 1.b690b47.1.1.cb73ce6.35.1510 from origin b690b47, one and one different, locally at commit cb73ce6, with a further 35 lines of change, built in 2015 in the tenth month. Day numbers are excluded for brevity, as there is already much uncertainty in the local changes and this field is only to indicate a rough level of freshness. Build numer starts with \"1.\" to avoid strange compile errors.\ncd \"${SOURCE_ROOT}\"\n\n# Skip setting the build number if this is a SANDBOXING build, since the helper probably needs a matching build number. Making them match is as easy as putting this script in both targets, though it's also easy to have one target read it from the other, but that's a task best left to the developer doing SANDBOXING builds since they would be in the position to make sure it is done correctly.\ngrep -q '^#define SANDBOXING *$' Flycut_Prefix.pch\nif [ \"0\" != \"$?\" ]\nthen\n\t\n\tORIGIN=$(git rev-parse --short remotes/origin/master)\n\tOFFSET=\".$(git status|sed -n '1,/^# *$/ p'|grep \"[0-9]\"|head -1|sed 's/^[^0-9]*//;s/[^0-9]*$//'|sed 's/[^0-9][^0-9]*/./')\"\n\tLOCAL=\".$(git rev-parse --short HEAD)\"\n\tUNCOMMITTED=\".$(git diff -b -w HEAD|grep \"^[+\\-]\"|grep -v \"^[+\\-][+\\-][+\\-] [ab]\"|wc -l|sed 's/[^0-9]//g')\"\n\tBUILD_YEAR_MONTH=\".$(date +\"%y%m\")\"\n\tif [ \".$ORIGIN\" == \"$LOCAL\" ]\n\tthen\n\t\tOFFSET=\"\"\n\t\tLOCAL=\"\"\n\t\tif [ \".0\" == \"$UNCOMMITTED\" ]\n\t\tthen\n\t\t\tUNCOMMITTED=\"\"\n\t\t\tBUILD_YEAR_MONTH=\"\"\n\t\tfi\n\tfi\n\tNEWVERSIONSTRING=\"1.$ORIGIN$OFFSET$LOCAL$UNCOMMITTED$BUILD_YEAR_MONTH\"\n\t/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $NEWVERSIONSTRING\" \"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\nfi\n";
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
77192A2223D6EA7A00EDB9BC /* Sources */ = {
isa = PBXSourcesBuildPhase;
@ -1302,7 +1321,7 @@
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OBJC_BRIDGING_HEADER = "Flycut-iOS-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
@ -1359,7 +1378,7 @@
SDKROOT = iphoneos;
SWIFT_OBJC_BRIDGING_HEADER = "Flycut-iOS-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
VALIDATE_PRODUCT = YES;
};
@ -1415,7 +1434,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flycut-iOS.app/Flycut-iOS";
};
name = Debug;
@ -1463,7 +1482,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flycut-iOS.app/Flycut-iOS";
VALIDATE_PRODUCT = YES;
};
@ -1518,7 +1537,7 @@
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TEST_TARGET_NAME = "Flycut-iOS";
};
name = Debug;
@ -1565,7 +1584,7 @@
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
SWIFT_VERSION = 3.0;
SWIFT_VERSION = 5.0;
TEST_TARGET_NAME = "Flycut-iOS";
VALIDATE_PRODUCT = YES;
};
@ -1614,11 +1633,14 @@
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Flycut_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = DEBUG;
GCC_PREPROCESSOR_DEFINITIONS = (
DEBUG,
FLYCUT_MAC,
);
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = /Applications;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
MACOSX_DEPLOYMENT_TARGET = 10.7;
MARKETING_VERSION = 1.9.6;
PRODUCT_BUNDLE_IDENTIFIER = com.generalarcade.flycut;
PRODUCT_NAME = Flycut;
@ -1647,12 +1669,12 @@
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = Flycut_Prefix.pch;
GCC_PREPROCESSOR_DEFINITIONS = "";
GCC_PREPROCESSOR_DEFINITIONS = FLYCUT_MAC;
"GCC_PREPROCESSOR_DEFINITIONS[arch=*]" = "";
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = /Applications;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.10;
MACOSX_DEPLOYMENT_TARGET = 10.7;
MARKETING_VERSION = 1.9.6;
PRODUCT_BUNDLE_IDENTIFIER = com.generalarcade.flycut;
PRODUCT_NAME = Flycut;

View file

@ -14,5 +14,7 @@
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-write</key>
<true/>
</dict>
</plist>

View file

@ -16,7 +16,14 @@
#import "FlycutOperator.h"
#import "MJCloudKitUserDefaultsSync/MJCloudKitUserDefaultsSync/MJCloudKitUserDefaultsSync.h"
@implementation FlycutOperator
#ifdef FLYCUT_MAC
#import "AppController.h"
#endif
@implementation FlycutOperator {
NSDateFormatter *dateFormatterForFilename;
NSDateFormatter *dateFormatterForDirectory;
}
- (id)init
{
@ -234,6 +241,7 @@
- (bool)saveFromStore:(FlycutStore*)store atIndex:(int)index withPrefix:(NSString*) prefix
{
#ifdef SANDBOXING
// This works fine when sandboxed. It just saves to ~/Library/Containers/.....
return NO;
# else
if ( [store jcListCount] > index ) {
@ -241,23 +249,92 @@
NSString *pbFullText = [self clippingStringWithCount:index inStore:store];
pbFullText = [pbFullText stringByReplacingOccurrencesOfString:@"\r" withString:@"\r\n"];
// Get the Desktop directory:
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDesktopDirectory, NSUserDomainMask, YES);
NSString *desktopDirectory = [paths objectAtIndex:0];
if (!dateFormatterForFilename) {
// Date formatters are time-expensive to create, so create once and reuse.
dateFormatterForFilename = [[NSDateFormatter alloc] init];
[dateFormatterForFilename setDateFormat:@"yyyy-MM-dd 'at' HH.mm.ss"];
}
// Get the timestamp string:
NSDate *currentDate = [NSDate date];
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:@"YYYY-MM-dd 'at' HH.mm.ss"];
NSString *dateString = [dateFormatter stringFromDate:currentDate];
NSString *dateString = [dateFormatterForFilename stringFromDate:currentDate];
// Make a file name to write the data to using the Desktop directory:
NSString *fileName = [NSString stringWithFormat:@"%@/%@%@Clipping %@.txt",
desktopDirectory, prefix, store == favoritesStore ? @"Favorite " : @"", dateString];
// Make a file name
NSString *fileName = [NSString stringWithFormat:@"%@%@Clipping %@.txt",
prefix, store == favoritesStore ? @"Favorite " : @"", dateString];
// Make a subdirectory, if doing autosave, to avoid a directory with too many files in it as that can make Finder effectively hang on launch if that directory were the desktop.
NSString *subdirectoryString = nil;
if ([prefix isEqualToString:@"Autosave "]) {
if (!dateFormatterForDirectory) {
// Date formatters are time-expensive to create, so create once and reuse.
dateFormatterForDirectory = [[NSDateFormatter alloc] init];
[dateFormatterForDirectory setDateFormat:@"'Autosave Clippings' yyyy/MM"];
}
subdirectoryString = [dateFormatterForDirectory stringFromDate:currentDate];
}
NSString *baseDirectoryString = nil;
NSString *fileNameWithPath = nil;
#ifdef FLYCUT_MAC
if ([AppController isAppSandboxed] && ![prefix isEqualToString:@"Autosave "]) {
// Since the app is sandboxed and this is not an auto-save, the user might want to say where to save it rather than just put it in ~/Library/Containers/..., so show a save dialog.
// Set the default name for the file and show the panel.
NSSavePanel* panel = [NSSavePanel savePanel];
[panel setNameFieldStringValue:fileName];
[panel setLevel:NSModalPanelWindowLevel];
[panel setAllowedFileTypes:@[@"txt"]];
if ([panel runModal] == NSFileHandlingPanelOKButton)
{
fileNameWithPath = [panel URL].path;
}
} else {
if ([prefix isEqualToString:@"Autosave "]) {
NSURL* autoSaveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"autoSaveToLocation"];
if (autoSaveToLocation) {
baseDirectoryString = autoSaveToLocation.path;
}
} else {
NSURL* saveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"saveToLocation"];
if (saveToLocation) {
baseDirectoryString = saveToLocation.path;
}
}
}
#endif
if (!fileNameWithPath) {
// An exact place to save wasn't set (like from a Save panel), so build one.
if (!baseDirectoryString) {
// Get the Desktop directory since nothing else was specified.
NSArray *paths = NSSearchPathForDirectoriesInDomains
(NSDesktopDirectory, NSUserDomainMask, YES);
NSString *desktopDirectory = [paths objectAtIndex:0];
baseDirectoryString = desktopDirectory;
}
if (subdirectoryString) {
// Apply a subdirectory / subdirectories.
NSString *directoryPath = [NSString stringWithFormat:@"%@/%@",
baseDirectoryString, subdirectoryString];
[[NSFileManager defaultManager] createDirectoryAtPath:directoryPath
withIntermediateDirectories:YES
attributes:nil
error:nil];
baseDirectoryString = directoryPath;
}
// Make a file name to write the data to using the base directory:
fileNameWithPath = [NSString stringWithFormat:@"%@/%@",
baseDirectoryString, fileName];
}
// Save content to the file
[pbFullText writeToFile:fileName
[pbFullText writeToFile:fileNameWithPath
atomically:NO
encoding:NSNonLossyASCIIStringEncoding
error:nil];
@ -303,7 +380,7 @@
return [self clippingStringWithCount:indexInt];
}
-(BOOL)shouldSkip:(NSString *)contents ofType:(NSString *)type
-(BOOL)shouldSkip:(NSString *)contents ofType:(NSString *)type fromAvailableTypes:(NSArray<NSString *> *)availableTypes
{
// Check to see if we are skipping passwords based on length and characters.
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPasswordFields"] )
@ -316,10 +393,10 @@
__block bool skipClipping = NO;
// Check the array of types to skip.
if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPboardTypes"] )
if ( availableTypes && [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPboardTypes"] )
{
NSSet *typesToSkip = [NSSet setWithArray: [[[[NSUserDefaults standardUserDefaults] stringForKey:@"skipPboardTypesList"] stringByReplacingOccurrencesOfString:@" " withString:@""] componentsSeparatedByString: @","]];
NSSet *pasteBoardTypes = [NSSet setWithArray: [[NSPasteboard generalPasteboard] types]];
NSSet *pasteBoardTypes = [NSSet setWithArray: availableTypes];
if ( [pasteBoardTypes intersectsSet: typesToSkip] )
{

View file

@ -8,6 +8,7 @@
#define kiCloudId @"iCloud.com.generalarcade.flycut"
#define kFlycutHelperId @"com.generalarcade.flycuthelper"
// The SANDBOXING flag isn't tightly coupled with the sandboxing entitlement, so this amounts to more of a code policy flag than a feature availability flag at the moment. [AppController isAppSandboxed] is more effective for feature availability checks.
//#define SANDBOXING
#ifdef DEBUG

View file

@ -10,6 +10,7 @@
//
#import "BezelWindow.h"
#import <AppKit/AppKit.h>
static const float lineHeight = 16;
@ -47,68 +48,70 @@ static const float lineHeight = 16;
sourceFieldBackground = [[RoundRecTextField alloc] initWithFrame:[self sourceFrame]];
[[self contentView] addSubview:sourceFieldBackground];
[sourceFieldBackground setEditable:NO];
[sourceFieldBackground setTextColor:[NSColor whiteColor]];
[sourceFieldBackground setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:.45]];
[sourceFieldBackground setDrawsBackground:YES];
[sourceFieldBackground setBordered:NO];
[sourceFieldBackground.textField setEditable:NO];
[sourceFieldBackground.textField setTextColor:[NSColor whiteColor]];
[sourceFieldBackground.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.45)];
[sourceFieldBackground.textField setBordered:NO];
sourceFieldApp = [[RoundRecTextField alloc] initWithFrame:[self sourceFrameLeft]];
[[self contentView] addSubview:sourceFieldApp];
[sourceFieldApp setEditable:NO];
[sourceFieldApp setTextColor:[NSColor whiteColor]];
[sourceFieldApp setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:0]];
[sourceFieldApp setDrawsBackground:YES];
[sourceFieldApp setBordered:NO];
[sourceFieldApp setAlignment:NSLeftTextAlignment];
[sourceFieldApp.textField setEditable:NO];
[sourceFieldApp.textField setTextColor:[NSColor whiteColor]];
[sourceFieldApp.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.0)];
[sourceFieldApp.textField setBordered:NO];
[sourceFieldApp.textField setAlignment:NSLeftTextAlignment];
NSMutableParagraphStyle *textParagraph = [[NSMutableParagraphStyle alloc] init];
[textParagraph setLineSpacing:100.0];
NSDictionary *attrDic = [NSDictionary dictionaryWithObjectsAndKeys:textParagraph, NSParagraphStyleAttributeName, nil];
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"" attributes:attrDic];
[sourceFieldApp setAllowsEditingTextAttributes:YES];
[sourceFieldApp setAttributedStringValue:attrString];
[sourceFieldApp.textField setAllowsEditingTextAttributes:YES];
[sourceFieldApp.textField setAttributedStringValue:attrString];
NSFont *font = [sourceFieldApp font];
NSFont *font = [sourceFieldApp.textField font];
NSFont *newFont = [NSFont fontWithName:[font fontName] size:font.pointSize*3/2];
[sourceFieldApp setFont:newFont];
[sourceFieldApp.textField setFont:newFont];
sourceFieldDate = [[RoundRecTextField alloc] initWithFrame:[self sourceFrameRight]];
[[self contentView] addSubview:sourceFieldDate];
[sourceFieldDate setEditable:NO];
[sourceFieldDate setTextColor:[NSColor whiteColor]];
[sourceFieldDate setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:0]];
[sourceFieldDate setDrawsBackground:YES];
[sourceFieldDate setBordered:NO];
[sourceFieldDate setAlignment:NSRightTextAlignment];
font = [sourceFieldDate font];
[sourceFieldDate.textField setEditable:NO];
[sourceFieldDate.textField setTextColor:[NSColor whiteColor]];
[sourceFieldDate.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.0)];
[sourceFieldDate.textField setBordered:NO];
[sourceFieldDate.textField setAlignment:NSRightTextAlignment];
font = [sourceFieldDate.textField font];
newFont = [NSFont fontWithName:[font fontName] size:font.pointSize*5/4];
[sourceFieldDate setFont:newFont];
[sourceFieldDate.textField setFont:newFont];
}
NSRect textFrame = [self textFrame];
textField = [[RoundRecTextField alloc] initWithFrame:textFrame];
[[self contentView] addSubview:textField];
[textField setEditable:NO];
[textField.textField setEditable:NO];
//[[textField cell] setScrollable:YES];
//[[textField cell] setWraps:NO];
[textField setTextColor:[NSColor whiteColor]];
[textField setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:.45]];
[textField setDrawsBackground:YES];
[textField setBordered:NO];
[textField setAlignment:NSLeftTextAlignment];
[textField.textField setTextColor:[NSColor whiteColor]];
[textField.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.45)];
[textField.textField setBordered:NO];
[textField.textField setAlignment:NSLeftTextAlignment];
NSRect charFrame = [self charFrame];
charField = [[RoundRecTextField alloc] initWithFrame:charFrame];
[[self contentView] addSubview:charField];
[charField setEditable:NO];
[charField setTextColor:[NSColor whiteColor]];
[charField setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:.45]];
[charField setDrawsBackground:YES];
[charField setBordered:NO];
[charField setAlignment:NSCenterTextAlignment];
[charField setStringValue:@"Empty"];
[charField.textField setEditable:NO];
[charField.textField setTextColor:[NSColor whiteColor]];
[charField.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.45)];
[charField.textField setBordered:NO];
[charField.textField setAlignment:NSCenterTextAlignment];
[charField.textField setStringValue:@"Empty"];
// Use Auto Layout for dynamic width.
charField.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[charField.bottomAnchor constraintEqualToAnchor:self.contentView.bottomAnchor constant:-charFrame.origin.y],
[charField.centerXAnchor constraintEqualToAnchor:self.contentView.centerXAnchor],
[charField.heightAnchor constraintEqualToConstant:charFrame.size.height],
]];
[self setInitialFirstResponder:textField];
return self;
@ -130,9 +133,9 @@ static const float lineHeight = 16;
NSRect charFrame = [self charFrame];
[charField setFrame:charFrame];
if (showSourceField)
[sourceFieldBackground setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:.45]];
[sourceFieldBackground.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.45)];
else if ( nil != sourceFieldApp )
[sourceFieldBackground setBackgroundColor:[NSColor colorWithCalibratedWhite:0.1 alpha:0]];
[sourceFieldBackground.background.layer setBackgroundColor:CGColorCreateGenericRGB(0.1, 0.1, 0.1, 0.0)];
showSourceField = savedShowSourceField;
@ -161,7 +164,6 @@ static const float lineHeight = 16;
{
NSRect frame = [self sourceFrame];
frame.size.width = frame.size.width * 1 / 3 - 5;
frame.origin.x += 5;
return frame;
}
@ -219,7 +221,7 @@ static const float lineHeight = 16;
[newChar retain];
[charString release];
charString = newChar;
[charField setStringValue:charString];
[charField.textField setStringValue:charString];
}
- (void)setText:(NSString *)newText
@ -231,7 +233,7 @@ static const float lineHeight = 16;
[newText retain];
[bezelText release];
bezelText = newText;
[textField setStringValue:bezelText];
[textField.textField setStringValue:bezelText];
}
- (void)setSourceIcon:(NSImage *)newSourceIcon
@ -250,7 +252,7 @@ static const float lineHeight = 16;
return;
// Ensure that the source will fit in the screen space available, and truncate nicely if need be.
NSDictionary *attributes = @{NSFontAttributeName: sourceFieldApp.font};
NSDictionary *attributes = @{NSFontAttributeName: sourceFieldApp.textField.font};
CGSize size = [newSource sizeWithAttributes:attributes]; // How big is this string when drawn in this font?
if (size.width >= sourceFieldApp.frame.size.width - 5)
{
@ -265,7 +267,7 @@ static const float lineHeight = 16;
[newSource retain];
[sourceText release];
sourceText = newSource;
[sourceFieldApp setStringValue:sourceText];
[sourceFieldApp.textField setStringValue:sourceText];
}
- (void)setDate:(NSString *)newDate
@ -275,7 +277,7 @@ static const float lineHeight = 16;
[newDate retain];
[dateText release];
dateText = newDate;
[sourceFieldDate setStringValue:dateText];
[sourceFieldDate.textField setStringValue:dateText];
}
- (void)setColor:(BOOL)value

View file

@ -12,9 +12,9 @@
#import <AppKit/AppKit.h>
@interface RoundRecTextField : NSTextField {
IBOutlet RoundRecTextField *characterBackground;
IBOutlet RoundRecTextField *textBackground;
}
@interface RoundRecTextField : NSView
@property (nonatomic, nonnull, readonly) NSTextField *textField;
@property (nonatomic, nonnull, readonly) NSView *background;
@end

View file

@ -13,41 +13,41 @@
#import "RoundRecTextField.h"
#import "RoundRecBezierPath.h"
// Okay, on doing some reading, the -best- way to handle this is probably to cache
// an NSImage on the init and then (as needed) composite it to the back of the view.
// We can then turn the rectangles on and off by compositing or not compositing the
// images.
// This can wait for another time.
@implementation RoundRecTextField
// We may want to make this a more flexible class sometime by taking radius as an argument.
// Until then, this is kind of useless code.
/*
- (id)initWithFrame:(NSRect)frame {
self = [super initWithFrame:frame];
if (self) {
// Initialization code here.
_background = [[NSView alloc] initWithFrame:frame];
[self addSubview:_background];
[_background setWantsLayer:YES];
[_background.layer setCornerRadius:8];
_background.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[_background.topAnchor constraintEqualToAnchor:self.topAnchor],
[_background.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[_background.leadingAnchor constraintEqualToAnchor:self.leadingAnchor],
[_background.trailingAnchor constraintEqualToAnchor:self.trailingAnchor],
]];
_textField = [[NSTextField alloc] initWithFrame:frame];
[self addSubview:_textField];
[_textField setDrawsBackground:NO];
// Set 8px leading and trailing padding.
_textField.translatesAutoresizingMaskIntoConstraints = NO;
[NSLayoutConstraint activateConstraints:@[
[_textField.topAnchor constraintEqualToAnchor:self.topAnchor],
[_textField.bottomAnchor constraintEqualToAnchor:self.bottomAnchor],
[_textField.leadingAnchor constraintEqualToAnchor:self.leadingAnchor constant:8],
[_textField.trailingAnchor constraintEqualToAnchor:self.trailingAnchor constant:-8],
]];
}
return self;
}
*/
- (BOOL)isOpaque {
return NO;
}
- (void)drawRect:(NSRect)rect {
// Oh, the hackishness.
NSBezierPath *roundedRec = [NSBezierPath bezierPathWithRoundRectInRect:rect radius:8];
[[self backgroundColor] set];
[roundedRec fill];
[self setDrawsBackground:NO];
// We might eventually want to pass [super drawRect] something smaller than rect, to ensure that we don't bleed over the corners
[super drawRect:rect];
[self setDrawsBackground:YES];
}
@end
@end

44
configureAppSandboxing.sh Executable file
View file

@ -0,0 +1,44 @@
#!/bin/bash
appSandboxing=false
defineSandboxing=false
if [ "$1" == "YES" ]
then
appSandboxing=true
defineSandboxing=false
elif [ "$1" == "NO" ]
then
appSandboxing=false
defineSandboxing=false
elif [ "$1" == "SANDBOXING" ]
then
appSandboxing=true
defineSandboxing=true
else
echo "Run with parameter YES or NO to enable or disable app sandboxing."
echo "Or with parameter SANDBOXING to enable or app sandboxing and define SANDBOXING"
echo " in the prefix header."
exit -1
fi
if [ "$defineSandboxing" == "true" ]
then
sed -i '' 's|^//\(#define SANDBOXING\) *$|\1|' Flycut_Prefix.pch
git add Flycut_Prefix.pch
else
sed -i '' 's|^\(#define SANDBOXING\) *$|//\1|' Flycut_Prefix.pch
git add Flycut_Prefix.pch
fi
for key in com.apple.security.app-sandbox com.apple.security.files.user-selected.read-write
do
for entitlements in $(git grep -l -e ">$key<")
do
/usr/libexec/PlistBuddy -c "Set :$key $appSandboxing" "$entitlements"
git add "$entitlements"
done
done
git commit -m "App Sandbox $(if [ "$appSandboxing" == "true" ] ; then echo "ON" ; else echo "OFF" ; fi)$(if [ "$defineSandboxing" == "true" ] ; then echo " with define" ; fi)"