Tree with reordering and core data storage + undo
This commit is contained in:
@@ -34,7 +34,6 @@
|
|||||||
54ACC28821061B3C0020715F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Main.xib; sourceTree = "<group>"; };
|
54ACC28821061B3C0020715F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/Main.xib; sourceTree = "<group>"; };
|
||||||
54ACC28A21061B3C0020715F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
54ACC28A21061B3C0020715F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||||
54ACC28B21061B3C0020715F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
54ACC28B21061B3C0020715F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
|
||||||
54ACC28D21061B3C0020715F /* baRSS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = baRSS.entitlements; sourceTree = "<group>"; };
|
|
||||||
54ACC29321061E270020715F /* NewsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NewsController.h; sourceTree = "<group>"; };
|
54ACC29321061E270020715F /* NewsController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NewsController.h; sourceTree = "<group>"; };
|
||||||
54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = "<group>"; };
|
54ACC29421061E270020715F /* NewsController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NewsController.m; sourceTree = "<group>"; };
|
||||||
54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = "<group>"; };
|
54ACC29621061FBA0020715F /* Preferences.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Preferences.h; sourceTree = "<group>"; };
|
||||||
@@ -103,7 +102,6 @@
|
|||||||
54ACC28721061B3C0020715F /* Main.xib */,
|
54ACC28721061B3C0020715F /* Main.xib */,
|
||||||
54ACC28A21061B3C0020715F /* Info.plist */,
|
54ACC28A21061B3C0020715F /* Info.plist */,
|
||||||
54ACC28B21061B3C0020715F /* main.m */,
|
54ACC28B21061B3C0020715F /* main.m */,
|
||||||
54ACC28D21061B3C0020715F /* baRSS.entitlements */,
|
|
||||||
54ACC28221061B3B0020715F /* DBv1.xcdatamodeld */,
|
54ACC28221061B3B0020715F /* DBv1.xcdatamodeld */,
|
||||||
);
|
);
|
||||||
path = baRSS;
|
path = baRSS;
|
||||||
@@ -146,7 +144,7 @@
|
|||||||
enabled = 0;
|
enabled = 0;
|
||||||
};
|
};
|
||||||
com.apple.Sandbox = {
|
com.apple.Sandbox = {
|
||||||
enabled = 1;
|
enabled = 0;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -325,21 +323,34 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||||
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
|
||||||
|
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = baRSS/baRSS.entitlements;
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = UY657LKNHJ;
|
DEVELOPMENT_TEAM = "";
|
||||||
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
|
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||||
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
|
GCC_WARN_PEDANTIC = YES;
|
||||||
|
GCC_WARN_SHADOW = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = YES;
|
||||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||||
@@ -352,8 +363,8 @@
|
|||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.baRSS;
|
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.baRSS;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
|
||||||
SWIFT_VERSION = 3.0;
|
|
||||||
};
|
};
|
||||||
name = Debug;
|
name = Debug;
|
||||||
};
|
};
|
||||||
@@ -361,21 +372,34 @@
|
|||||||
isa = XCBuildConfiguration;
|
isa = XCBuildConfiguration;
|
||||||
buildSettings = {
|
buildSettings = {
|
||||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||||
|
CLANG_ANALYZER_SECURITY_FLOATLOOPCOUNTER = YES;
|
||||||
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_RAND = YES;
|
||||||
|
CLANG_ANALYZER_SECURITY_INSECUREAPI_STRCPY = YES;
|
||||||
CLANG_ENABLE_MODULES = YES;
|
CLANG_ENABLE_MODULES = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_INTEGER = YES;
|
||||||
|
CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES;
|
||||||
|
CLANG_WARN_ASSIGN_ENUM = YES;
|
||||||
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
CLANG_WARN_CXX0X_EXTENSIONS = YES;
|
||||||
|
CLANG_WARN_IMPLICIT_SIGN_CONVERSION = YES;
|
||||||
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
CLANG_WARN_OBJC_EXPLICIT_OWNERSHIP_TYPE = YES;
|
||||||
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
|
CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES;
|
||||||
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
CLANG_WARN_SUSPICIOUS_IMPLICIT_CONVERSION = YES;
|
||||||
CODE_SIGN_ENTITLEMENTS = baRSS/baRSS.entitlements;
|
CODE_SIGN_IDENTITY = "";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Manual;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
DEVELOPMENT_TEAM = UY657LKNHJ;
|
DEVELOPMENT_TEAM = "";
|
||||||
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
|
EMBED_ASSET_PACKS_IN_PRODUCT_BUNDLE = NO;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)",
|
"$(PROJECT_DIR)",
|
||||||
);
|
);
|
||||||
|
GCC_WARN_ABOUT_MISSING_FIELD_INITIALIZERS = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_NEWLINE = YES;
|
||||||
|
GCC_WARN_ABOUT_MISSING_PROTOTYPES = YES;
|
||||||
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
GCC_WARN_HIDDEN_VIRTUAL_FUNCTIONS = YES;
|
||||||
|
GCC_WARN_INITIALIZER_NOT_FULLY_BRACKETED = YES;
|
||||||
|
GCC_WARN_PEDANTIC = YES;
|
||||||
|
GCC_WARN_SHADOW = YES;
|
||||||
GCC_WARN_SIGN_COMPARE = YES;
|
GCC_WARN_SIGN_COMPARE = YES;
|
||||||
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
GCC_WARN_STRICT_SELECTOR_MATCH = YES;
|
||||||
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
GCC_WARN_UNKNOWN_PRAGMAS = YES;
|
||||||
@@ -388,7 +412,7 @@
|
|||||||
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
MACOSX_DEPLOYMENT_TARGET = 10.12;
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.baRSS;
|
PRODUCT_BUNDLE_IDENTIFIER = de.relikd.baRSS;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
SWIFT_VERSION = 3.0;
|
PROVISIONING_PROFILE_SPECIFIER = "";
|
||||||
};
|
};
|
||||||
name = Release;
|
name = Release;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -58,23 +58,15 @@
|
|||||||
@synchronized (self) {
|
@synchronized (self) {
|
||||||
if (_persistentContainer == nil) {
|
if (_persistentContainer == nil) {
|
||||||
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DBv1"];
|
_persistentContainer = [[NSPersistentContainer alloc] initWithName:@"DBv1"];
|
||||||
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
|
[_persistentContainer loadPersistentStoresWithCompletionHandler:^(NSPersistentStoreDescription *storeDescription, NSError *error) {
|
||||||
if (error != nil) {
|
if (error != nil) {
|
||||||
// Replace this implementation with code to handle the error appropriately.
|
NSLog(@"Couldn't read NSPersistentContainer: %@, %@", error, error.userInfo);
|
||||||
// abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
|
||||||
|
|
||||||
/*
|
|
||||||
Typical reasons for an error here include:
|
|
||||||
* The parent directory does not exist, cannot be created, or disallows writing.
|
|
||||||
* The persistent store is not accessible, due to permissions or data protection when the device is locked.
|
|
||||||
* The device is out of space.
|
|
||||||
* The store could not be migrated to the current model version.
|
|
||||||
Check the error message to determine what the actual problem was.
|
|
||||||
*/
|
|
||||||
NSLog(@"Unresolved error %@, %@", error, error.userInfo);
|
|
||||||
abort();
|
abort();
|
||||||
}
|
}
|
||||||
}];
|
}];
|
||||||
|
NSUndoManager *um = [[NSUndoManager alloc] init];
|
||||||
|
um.levelsOfUndo = 30;
|
||||||
|
_persistentContainer.viewContext.undoManager = um;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,16 +19,19 @@
|
|||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</customObject>
|
||||||
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
<customObject id="YLy-65-1bz" customClass="NSFontManager"/>
|
||||||
<customObject id="he0-Eb-PDA" customClass="NewsController">
|
<treeController mode="entity" entityName="FeedConfig" fetchPredicateFormat="parent == nil" automaticallyPreparesContent="YES" childrenKeyPath="children" leafKeyPath="type" id="1oZ-Uo-mIu" customClass="NewsController">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="openUnreadItem" destination="Qqw-Xj-oA5" id="8df-is-Qop"/>
|
<binding destination="Voe-Tx-rLC" name="managedObjectContext" keyPath="self.persistentContainer.viewContext" id="Q1f-VN-9qq"/>
|
||||||
<outlet property="pauseItem" destination="D7r-Vb-9eO" id="o7e-jD-3Yj"/>
|
<outlet property="openUnreadItem" destination="Qqw-Xj-oA5" id="JN3-Ej-EPc"/>
|
||||||
<outlet property="updateAllItem" destination="wgp-fa-8Wj" id="edP-bQ-bIM"/>
|
<outlet property="outlineView" destination="hKk-G1-1po" id="Z4y-uD-Zse"/>
|
||||||
|
<outlet property="pauseItem" destination="D7r-Vb-9eO" id="8Cu-bX-0uT"/>
|
||||||
|
<outlet property="updateAllItem" destination="wgp-fa-8Wj" id="dI0-8A-qaY"/>
|
||||||
</connections>
|
</connections>
|
||||||
</customObject>
|
</treeController>
|
||||||
<customObject id="bgB-po-1IK" customClass="Preferences">
|
<customObject id="bgB-po-1IK" customClass="Preferences">
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="appDelegate" destination="Voe-Tx-rLC" id="1aD-dC-e6r"/>
|
<outlet property="feedsOutline" destination="hKk-G1-1po" id="jcw-Fq-DyK"/>
|
||||||
|
<outlet property="newsController" destination="1oZ-Uo-mIu" id="hAk-g4-Oii"/>
|
||||||
<outlet property="toolbar" destination="wLj-fD-HpE" id="bMA-dd-1H1"/>
|
<outlet property="toolbar" destination="wLj-fD-HpE" id="bMA-dd-1H1"/>
|
||||||
<outlet property="viewFeeds" destination="EwH-fT-yW8" id="pmQ-as-O2V"/>
|
<outlet property="viewFeeds" destination="EwH-fT-yW8" id="pmQ-as-O2V"/>
|
||||||
<outlet property="viewGeneral" destination="8H4-sI-Ub8" id="lWU-Il-4in"/>
|
<outlet property="viewGeneral" destination="8H4-sI-Ub8" id="lWU-Il-4in"/>
|
||||||
@@ -40,26 +43,26 @@
|
|||||||
<menuItem title="Pause Updates" id="D7r-Vb-9eO">
|
<menuItem title="Pause Updates" id="D7r-Vb-9eO">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="pauseUpdates:" target="he0-Eb-PDA" id="9Nm-b4-h4h"/>
|
<action selector="pauseUpdates:" target="1oZ-Uo-mIu" id="WaC-Gv-Jlh"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Update All Feeds" id="wgp-fa-8Wj">
|
<menuItem title="Update All Feeds" id="wgp-fa-8Wj">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="updateAllFeeds:" target="he0-Eb-PDA" id="z7p-Ax-hgc"/>
|
<action selector="updateAllFeeds:" target="1oZ-Uo-mIu" id="5yX-Gc-9Qg"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Open All Unread" id="Qqw-Xj-oA5">
|
<menuItem title="Open All Unread" id="Qqw-Xj-oA5">
|
||||||
<modifierMask key="keyEquivalentModifierMask"/>
|
<modifierMask key="keyEquivalentModifierMask"/>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="openAllUnread:" target="he0-Eb-PDA" id="bgo-Tt-0sv"/>
|
<action selector="openAllUnread:" target="1oZ-Uo-mIu" id="dpt-U6-GPp"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem isSeparatorItem="YES" id="ld2-b0-07a"/>
|
<menuItem isSeparatorItem="YES" id="ld2-b0-07a"/>
|
||||||
<menuItem isSeparatorItem="YES" id="1VS-wM-kTc"/>
|
<menuItem isSeparatorItem="YES" id="1VS-wM-kTc"/>
|
||||||
<menuItem title="Preferences" keyEquivalent="," id="VFY-eR-2EA">
|
<menuItem title="Preferences" keyEquivalent="," id="VFY-eR-2EA">
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="showWindow:" target="bgB-po-1IK" id="eBk-Wq-1eA"/>
|
<action selector="makeKeyAndOrderFront:" target="ai3-RW-O8g" id="qaE-j2-fux"/>
|
||||||
</connections>
|
</connections>
|
||||||
</menuItem>
|
</menuItem>
|
||||||
<menuItem title="Quit" keyEquivalent="q" id="Nb6-yK-a1A">
|
<menuItem title="Quit" keyEquivalent="q" id="Nb6-yK-a1A">
|
||||||
@@ -318,14 +321,14 @@
|
|||||||
<rect key="frame" x="1" y="0.0" width="318" height="306"/>
|
<rect key="frame" x="1" y="0.0" width="318" height="306"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" multipleSelection="NO" autosaveColumns="NO" rowSizeStyle="automatic" headerView="sii-NE-JkJ" viewBased="YES" indentationPerLevel="16" outlineTableColumn="Lb1-9n-wlc" id="hKk-G1-1po">
|
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" alternatingRowBackgroundColors="YES" autosaveColumns="NO" headerView="sii-NE-JkJ" indentationPerLevel="16" outlineTableColumn="Lb1-9n-wlc" id="hKk-G1-1po">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="318" height="283"/>
|
<rect key="frame" x="0.0" y="0.0" width="318" height="283"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<size key="intercellSpacing" width="3" height="2"/>
|
<size key="intercellSpacing" width="3" height="2"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
<tableColumns>
|
<tableColumns>
|
||||||
<tableColumn identifier="" editable="NO" width="252.5" minWidth="40" maxWidth="1000" id="Lb1-9n-wlc">
|
<tableColumn identifier="" width="252.5" minWidth="40" maxWidth="1000" id="Lb1-9n-wlc">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -337,29 +340,17 @@
|
|||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
|
||||||
<prototypeCellViews>
|
<connections>
|
||||||
<tableCellView id="6yl-oX-eNn">
|
<binding destination="1oZ-Uo-mIu" name="value" keyPath="arrangedObjects.name" id="Lgo-HL-51z">
|
||||||
<rect key="frame" x="1" y="1" width="253" height="17"/>
|
<dictionary key="options">
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<bool key="NSConditionallySetsEditable" value="YES"/>
|
||||||
<subviews>
|
<string key="NSNullPlaceholder">TUUP</string>
|
||||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Z97-we-rgn">
|
</dictionary>
|
||||||
<rect key="frame" x="0.0" y="0.0" width="253" height="17"/>
|
</binding>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
|
</connections>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="FGY-QQ-joq">
|
|
||||||
<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>
|
|
||||||
</subviews>
|
|
||||||
<connections>
|
|
||||||
<outlet property="textField" destination="Z97-we-rgn" id="Xfe-pC-8kn"/>
|
|
||||||
</connections>
|
|
||||||
</tableCellView>
|
|
||||||
</prototypeCellViews>
|
|
||||||
</tableColumn>
|
</tableColumn>
|
||||||
<tableColumn identifier="" editable="NO" width="59.5" minWidth="40" maxWidth="1000" id="8st-OH-BXG">
|
<tableColumn identifier="" width="59.5" minWidth="40" maxWidth="1000" id="8st-OH-BXG">
|
||||||
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Update">
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Refresh">
|
||||||
<font key="font" metaFont="smallSystem"/>
|
<font key="font" metaFont="smallSystem"/>
|
||||||
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
@@ -369,11 +360,13 @@
|
|||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<binding destination="1oZ-Uo-mIu" name="value" keyPath="arrangedObjects.refresh" id="R51-fy-Ufu"/>
|
||||||
|
</connections>
|
||||||
</tableColumn>
|
</tableColumn>
|
||||||
</tableColumns>
|
</tableColumns>
|
||||||
<connections>
|
<connections>
|
||||||
<outlet property="dataSource" destination="he0-Eb-PDA" id="bid-ep-fYr"/>
|
<outlet property="dataSource" destination="1oZ-Uo-mIu" id="sch-o5-yEm"/>
|
||||||
<outlet property="delegate" destination="he0-Eb-PDA" id="FV8-3T-QDV"/>
|
|
||||||
</connections>
|
</connections>
|
||||||
</outlineView>
|
</outlineView>
|
||||||
</subviews>
|
</subviews>
|
||||||
@@ -399,7 +392,8 @@
|
|||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="addFeed:" target="he0-Eb-PDA" id="dC1-tw-xxy"/>
|
<action selector="add:" target="1oZ-Uo-mIu" id="9rc-sz-RXa"/>
|
||||||
|
<binding destination="1oZ-Uo-mIu" name="enabled" keyPath="canInsert" id="1xq-Nj-Acq"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button toolTip="Delete item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kwZ-TS-nM7">
|
<button toolTip="Delete item" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kwZ-TS-nM7">
|
||||||
@@ -410,7 +404,8 @@
|
|||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="removeFeed:" target="he0-Eb-PDA" id="C4r-3D-ARB"/>
|
<action selector="remove:" target="1oZ-Uo-mIu" id="mph-g8-8J0"/>
|
||||||
|
<binding destination="1oZ-Uo-mIu" name="enabled" keyPath="canRemove" id="9oY-fm-uq0"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button toolTip="Add new line separator" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BRb-Je-jM4">
|
<button toolTip="Add new line separator" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BRb-Je-jM4">
|
||||||
@@ -421,7 +416,7 @@
|
|||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="addSeparator:" target="he0-Eb-PDA" id="68L-xT-tM9"/>
|
<action selector="addSeparator:" target="1oZ-Uo-mIu" id="bs4-Jk-EWD"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button toolTip="Add new grouping folder" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kQF-LC-quC">
|
<button toolTip="Add new grouping folder" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="kQF-LC-quC">
|
||||||
@@ -432,7 +427,7 @@
|
|||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="system"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="addGroup:" target="he0-Eb-PDA" id="82S-0f-6d9"/>
|
<action selector="addGroup:" target="1oZ-Uo-mIu" id="8MO-eQ-XcJ"/>
|
||||||
</connections>
|
</connections>
|
||||||
</button>
|
</button>
|
||||||
<button hidden="YES" toolTip="Import or Export data" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XaQ-S9-guo">
|
<button hidden="YES" toolTip="Import or Export data" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="XaQ-S9-guo">
|
||||||
|
|||||||
@@ -10,8 +10,19 @@
|
|||||||
<attribute name="published" optional="YES" attributeType="Transformable" customClassName="NSArray" syncable="YES"/>
|
<attribute name="published" optional="YES" attributeType="Transformable" customClassName="NSArray" syncable="YES"/>
|
||||||
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="subtitle" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="title" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<relationship name="config" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedConfig" inverseName="feed" inverseEntity="FeedConfig" syncable="YES"/>
|
||||||
<relationship name="items" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="FeedItem" inverseName="feed" inverseEntity="FeedItem" syncable="YES"/>
|
<relationship name="items" optional="YES" toMany="YES" deletionRule="Cascade" ordered="YES" destinationEntity="FeedItem" inverseName="feed" inverseEntity="FeedItem" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
|
<entity name="FeedConfig" representedClassName="FeedConfig" syncable="YES" codeGenerationType="class">
|
||||||
|
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="refresh" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="sortIndex" optional="YES" attributeType="Integer 32" defaultValueString="0" usesScalarValueType="YES" syncable="YES"/>
|
||||||
|
<attribute name="type" optional="YES" attributeType="Integer 16" defaultValueString="1" usesScalarValueType="YES" syncable="YES"/>
|
||||||
|
<attribute name="url" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<relationship name="children" optional="YES" toMany="YES" deletionRule="Cascade" destinationEntity="FeedConfig" inverseName="parent" inverseEntity="FeedConfig" syncable="YES"/>
|
||||||
|
<relationship name="feed" optional="YES" maxCount="1" deletionRule="Cascade" destinationEntity="Feed" inverseName="config" inverseEntity="Feed" syncable="YES"/>
|
||||||
|
<relationship name="parent" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedConfig" inverseName="children" inverseEntity="FeedConfig" syncable="YES"/>
|
||||||
|
</entity>
|
||||||
<entity name="FeedItem" representedClassName="FeedItem" syncable="YES" codeGenerationType="class">
|
<entity name="FeedItem" representedClassName="FeedItem" syncable="YES" codeGenerationType="class">
|
||||||
<attribute name="author" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="author" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
<attribute name="link" optional="YES" attributeType="String" syncable="YES"/>
|
<attribute name="link" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
@@ -27,8 +38,9 @@
|
|||||||
<relationship name="feedItem" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedItem" inverseName="tags" inverseEntity="FeedItem" syncable="YES"/>
|
<relationship name="feedItem" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="FeedItem" inverseName="tags" inverseEntity="FeedItem" syncable="YES"/>
|
||||||
</entity>
|
</entity>
|
||||||
<elements>
|
<elements>
|
||||||
<element name="FeedItem" positionX="-36" positionY="-36" width="128" height="165"/>
|
<element name="Feed" positionX="-209" positionY="-3" width="128" height="210"/>
|
||||||
<element name="FeedTag" positionX="0" positionY="54" width="128" height="75"/>
|
<element name="FeedConfig" positionX="-20" positionY="-126" width="128" height="165"/>
|
||||||
<element name="Feed" positionX="27" positionY="9" width="128" height="195"/>
|
<element name="FeedItem" positionX="-20" positionY="81" width="128" height="165"/>
|
||||||
|
<element name="FeedTag" positionX="187" positionY="171" width="128" height="75"/>
|
||||||
</elements>
|
</elements>
|
||||||
</model>
|
</model>
|
||||||
@@ -22,5 +22,10 @@
|
|||||||
|
|
||||||
#import <Cocoa/Cocoa.h>
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
@interface NewsController : NSViewController <NSOutlineViewDataSource, NSOutlineViewDelegate>
|
@interface NewsController : NSTreeController <NSOutlineViewDataSource, NSOutlineViewDelegate>
|
||||||
|
- (IBAction)addFeed:(NSButton *)sender;
|
||||||
|
- (IBAction)addGroup:(NSButton *)sender;
|
||||||
|
- (IBAction)addSeparator:(NSButton *)sender;
|
||||||
|
|
||||||
|
- (NSString*)copyDescriptionOfSelectedItems;
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -26,22 +26,28 @@
|
|||||||
#import "DBv1+CoreDataModel.h"
|
#import "DBv1+CoreDataModel.h"
|
||||||
|
|
||||||
@interface NewsController ()
|
@interface NewsController ()
|
||||||
|
@property (weak) IBOutlet NSOutlineView *outlineView;
|
||||||
@property (weak) IBOutlet NSMenuItem *pauseItem;
|
@property (weak) IBOutlet NSMenuItem *pauseItem;
|
||||||
@property (weak) IBOutlet NSMenuItem *updateAllItem;
|
@property (weak) IBOutlet NSMenuItem *updateAllItem;
|
||||||
@property (weak) IBOutlet NSMenuItem *openUnreadItem;
|
@property (weak) IBOutlet NSMenuItem *openUnreadItem;
|
||||||
@property (retain) NSManagedObjectContext *managedContext;
|
|
||||||
|
@property (strong) NSArray<NSTreeNode*> *currentlyDraggedNodes;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation NewsController
|
@implementation NewsController
|
||||||
|
|
||||||
|
// Declare a string constant for the drag type - to be used when writing and retrieving pasteboard data...
|
||||||
|
static NSString *dragNodeType = @"baRSS-feed-type";
|
||||||
|
|
||||||
- (void)awakeFromNib {
|
- (void)awakeFromNib {
|
||||||
[super awakeFromNib];
|
[super awakeFromNib];
|
||||||
self.managedContext = [((AppDelegate*)[NSApp delegate]) persistentContainer].viewContext;
|
// Set the outline view to accept the custom drag type AbstractTreeNodeType...
|
||||||
|
[self.outlineView registerForDraggedTypes:[NSArray arrayWithObject:dragNodeType]];
|
||||||
|
[self setSortDescriptors:[NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:@"sortIndex" ascending:YES]]];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)pauseUpdates:(NSMenuItem *)sender {
|
- (IBAction)pauseUpdates:(NSMenuItem *)sender {
|
||||||
NSLog(@"pause");
|
NSLog(@"pause");
|
||||||
NSLog(@"%@", self.managedContext);
|
|
||||||
}
|
}
|
||||||
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
|
- (IBAction)updateAllFeeds:(NSMenuItem *)sender {
|
||||||
NSLog(@"update all");
|
NSLog(@"update all");
|
||||||
@@ -49,7 +55,7 @@
|
|||||||
NSLog(@"obj = %@", obj);
|
NSLog(@"obj = %@", obj);
|
||||||
// TODO: check status code
|
// TODO: check status code
|
||||||
/*
|
/*
|
||||||
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:self.managedContext];
|
Feed *a = [[Feed alloc] initWithEntity:Feed.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
||||||
a.title = obj[@"feed"][@"title"];
|
a.title = obj[@"feed"][@"title"];
|
||||||
a.subtitle = obj[@"feed"][@"subtitle"];
|
a.subtitle = obj[@"feed"][@"subtitle"];
|
||||||
a.author = obj[@"feed"][@"author"];
|
a.author = obj[@"feed"][@"author"];
|
||||||
@@ -60,7 +66,7 @@
|
|||||||
a.date = obj[@"header"][@"date"];
|
a.date = obj[@"header"][@"date"];
|
||||||
a.modified = obj[@"header"][@"modified"];
|
a.modified = obj[@"header"][@"modified"];
|
||||||
for (NSDictionary *entry in obj[@"entries"]) {
|
for (NSDictionary *entry in obj[@"entries"]) {
|
||||||
FeedItem *b = [[FeedItem alloc] initWithEntity:FeedItem.entity insertIntoManagedObjectContext:self.managedContext];
|
FeedItem *b = [[FeedItem alloc] initWithEntity:FeedItem.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
||||||
b.title = entry[@"title"];
|
b.title = entry[@"title"];
|
||||||
b.subtitle = entry[@"subtitle"];
|
b.subtitle = entry[@"subtitle"];
|
||||||
b.author = entry[@"author"];
|
b.author = entry[@"author"];
|
||||||
@@ -68,45 +74,157 @@
|
|||||||
b.published = entry[@"published"];
|
b.published = entry[@"published"];
|
||||||
b.summary = entry[@"summary"];
|
b.summary = entry[@"summary"];
|
||||||
for (NSString *tag in entry[@"tags"]) {
|
for (NSString *tag in entry[@"tags"]) {
|
||||||
FeedTag *c = [[FeedTag alloc] initWithEntity:FeedTag.entity insertIntoManagedObjectContext:self.managedContext];
|
FeedTag *c = [[FeedTag alloc] initWithEntity:FeedTag.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
||||||
c.name = tag;
|
c.name = tag;
|
||||||
[b addTagsObject:c];
|
[b addTagsObject:c];
|
||||||
}
|
}
|
||||||
[a addItemsObject:b];
|
[a addItemsObject:b];
|
||||||
}*/
|
}*/
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)openAllUnread:(NSMenuItem *)sender {
|
- (IBAction)openAllUnread:(NSMenuItem *)sender {
|
||||||
NSLog(@"all unread");
|
NSLog(@"all unread");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)addFeed:(NSButton *)sender {
|
- (IBAction)addFeed:(NSButton *)sender {
|
||||||
NSLog(@"add feed");
|
NSLog(@"add feed");
|
||||||
NSLog(@"%@", self.managedContext);
|
|
||||||
}
|
|
||||||
- (IBAction)removeFeed:(NSButton *)sender {
|
|
||||||
NSLog(@"del feed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)addGroup:(NSButton *)sender {
|
- (IBAction)addGroup:(NSButton *)sender {
|
||||||
|
FeedConfig *g = [[FeedConfig alloc] initWithEntity:FeedConfig.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
||||||
|
g.name = @"Group";
|
||||||
|
g.type = 0;
|
||||||
NSLog(@"add group");
|
NSLog(@"add group");
|
||||||
}
|
}
|
||||||
|
|
||||||
- (IBAction)addSeparator:(NSButton *)sender {
|
- (IBAction)addSeparator:(NSButton *)sender {
|
||||||
NSLog(@"add separator");
|
NSLog(@"add separator");
|
||||||
|
// [self.managedObjectContext.undoManager beginUndoGrouping];
|
||||||
|
// [self.managedObjectContext.undoManager endUndoGrouping];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (NSString*)copyDescriptionOfSelectedItems {
|
||||||
- (NSInteger)outlineView:(NSOutlineView *)outlineView numberOfChildrenOfItem:(id)item {
|
NSMutableString *str = [[NSMutableString alloc] init];
|
||||||
return 1;
|
for (FeedConfig *item in self.selectedObjects) {
|
||||||
|
[self traverseChildren:item appendString:str indentation:0];
|
||||||
|
}
|
||||||
|
[[NSPasteboard generalPasteboard] clearContents];
|
||||||
|
[[NSPasteboard generalPasteboard] setString:str forType:NSPasteboardTypeString];
|
||||||
|
NSLog(@"%@", str);
|
||||||
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (BOOL)outlineView:(NSOutlineView *)outlineView isItemExpandable:(id)item {
|
- (void)traverseChildren:(FeedConfig*)obj appendString:(NSMutableString*)str indentation:(int)indent {
|
||||||
return NO;
|
for (int i = indent; i > 0; i--) {
|
||||||
|
[str appendString:@" "];
|
||||||
|
}
|
||||||
|
switch (obj.type) {
|
||||||
|
case 0: [str appendFormat:@"%@:\n", obj.name]; break; // Group
|
||||||
|
case 2: [str appendString:@"-------------\n"]; break; // Separator
|
||||||
|
default: [str appendFormat:@"%@ (%@) - %@\n", obj.name, obj.url, obj.refresh];
|
||||||
|
}
|
||||||
|
for (FeedConfig *child in obj.children) {
|
||||||
|
[self traverseChildren:child appendString:str indentation:indent + 1];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)outlineView:(NSOutlineView *)outlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item {
|
- (FeedConfig*)insertNewItemAtCurrentSelection {
|
||||||
return @"du";
|
FeedConfig *selected = [[[self arrangedObjects] descendantNodeAtIndexPath:[self selectionIndexPath]] representedObject];
|
||||||
|
FeedConfig *newItem = [[FeedConfig alloc] initWithEntity:FeedConfig.entity insertIntoManagedObjectContext:self.managedObjectContext];
|
||||||
|
if (selected.type == 0) // a group
|
||||||
|
newItem.sortIndex = (int32_t)selected.children.count;
|
||||||
|
else
|
||||||
|
newItem.sortIndex = selected.sortIndex + 1;
|
||||||
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (id)outlineView:(NSOutlineView *)outlineView child:(NSInteger)index ofItem:(id)item {
|
- (void)incrementIndicesBy:(int)val forSubsequentNodes:(NSIndexPath*)path {
|
||||||
return @"hi";
|
NSIndexPath *parentPath = [path indexPathByRemovingLastIndex];
|
||||||
|
NSTreeNode *root = [self arrangedObjects];
|
||||||
|
if (parentPath.length > 0)
|
||||||
|
root = [root descendantNodeAtIndexPath:parentPath];
|
||||||
|
|
||||||
|
for (NSUInteger i = [path indexAtPosition:path.length - 1]; i < root.childNodes.count; i++) {
|
||||||
|
((FeedConfig*)[root.childNodes[i] representedObject]).sortIndex += val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#pragma mark - Dragging Support, Data Source Delegate
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard {
|
||||||
|
[self.managedObjectContext.undoManager beginUndoGrouping];
|
||||||
|
[pboard declareTypes:[NSArray arrayWithObject:dragNodeType] owner:self];
|
||||||
|
[pboard setString:@"dragging" forType:dragNodeType];
|
||||||
|
self.currentlyDraggedNodes = items;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)outlineView:(NSOutlineView *)outlineView draggingSession:(NSDraggingSession *)session endedAtPoint:(NSPoint)screenPoint operation:(NSDragOperation)operation {
|
||||||
|
self.currentlyDraggedNodes = nil;
|
||||||
|
[self.managedObjectContext.undoManager endUndoGrouping];
|
||||||
|
if ([self.managedObjectContext hasChanges]) {
|
||||||
|
NSError *err;
|
||||||
|
[self.managedObjectContext save:&err];
|
||||||
|
if (err) NSLog(@"Error: %@", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index {
|
||||||
|
NSArray<NSTreeNode *> *dstChildren = [item childNodes];
|
||||||
|
if (!item || !dstChildren)
|
||||||
|
dstChildren = [self arrangedObjects].childNodes;
|
||||||
|
|
||||||
|
bool isFolderDrag = (index == -1);
|
||||||
|
NSUInteger insertIndex = (isFolderDrag ? dstChildren.count : (NSUInteger)index);
|
||||||
|
// index where the items will be moved to, but not final since items above can vanish
|
||||||
|
NSIndexPath *dest = [item indexPath];
|
||||||
|
if (!dest) dest = [NSIndexPath indexPathWithIndex:insertIndex];
|
||||||
|
else dest = [dest indexPathByAddingIndex:insertIndex];
|
||||||
|
|
||||||
|
// decrement index for every item that is dragged from the same location (above the destination)
|
||||||
|
NSUInteger updateIndex = insertIndex;
|
||||||
|
for (NSTreeNode *node in self.currentlyDraggedNodes) {
|
||||||
|
NSIndexPath *nodesPath = [node indexPath];
|
||||||
|
if ([[nodesPath indexPathByRemovingLastIndex] isEqualTo:[dest indexPathByRemovingLastIndex]] &&
|
||||||
|
insertIndex > [nodesPath indexAtPosition:nodesPath.length - 1])
|
||||||
|
{
|
||||||
|
--updateIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrement sort indices at source
|
||||||
|
for (NSTreeNode *node in self.currentlyDraggedNodes)
|
||||||
|
[self incrementIndicesBy:-1 forSubsequentNodes:[node indexPath]];
|
||||||
|
// increment sort indices at destination
|
||||||
|
if (!isFolderDrag)
|
||||||
|
[self incrementIndicesBy:(int)self.currentlyDraggedNodes.count forSubsequentNodes:dest];
|
||||||
|
|
||||||
|
// move items
|
||||||
|
[self moveNodes:self.currentlyDraggedNodes toIndexPath:dest];
|
||||||
|
|
||||||
|
// set sort indices for dragged items
|
||||||
|
for (NSUInteger i = 0; i < self.currentlyDraggedNodes.count; i++) {
|
||||||
|
FeedConfig *fc = [self.currentlyDraggedNodes[i] representedObject];
|
||||||
|
fc.sortIndex = (int32_t)(updateIndex + i);
|
||||||
|
}
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index {
|
||||||
|
FeedConfig *fc = [(NSTreeNode*)item representedObject];
|
||||||
|
if (index == -1 && fc.type != 0) { // if drag is on specific item and that item isnt a group
|
||||||
|
return NSDragOperationNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
NSTreeNode *parent = item;
|
||||||
|
while (parent != nil) {
|
||||||
|
for (NSTreeNode *node in self.currentlyDraggedNodes) {
|
||||||
|
if (parent == node)
|
||||||
|
return NSDragOperationNone; // cannot move items into a child of its own
|
||||||
|
}
|
||||||
|
parent = [parent parentNode];
|
||||||
|
}
|
||||||
|
return NSDragOperationGeneric;
|
||||||
}
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|||||||
@@ -21,13 +21,15 @@
|
|||||||
// SOFTWARE.
|
// SOFTWARE.
|
||||||
|
|
||||||
#import "Preferences.h"
|
#import "Preferences.h"
|
||||||
#import "AppDelegate.h"
|
#import "NewsController.h"
|
||||||
|
|
||||||
@interface Preferences ()
|
@interface Preferences ()
|
||||||
@property (weak) IBOutlet NSToolbar *toolbar;
|
@property (weak) IBOutlet NSToolbar *toolbar;
|
||||||
@property (weak) IBOutlet NSView *viewGeneral;
|
@property (weak) IBOutlet NSView *viewGeneral;
|
||||||
@property (weak) IBOutlet NSView *viewFeeds;
|
@property (weak) IBOutlet NSView *viewFeeds;
|
||||||
@property (weak) IBOutlet AppDelegate *appDelegate;
|
|
||||||
|
@property (weak) IBOutlet NewsController *newsController;
|
||||||
|
@property (weak) IBOutlet NSOutlineView *feedsOutline;
|
||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation Preferences
|
@implementation Preferences
|
||||||
@@ -53,12 +55,33 @@
|
|||||||
|
|
||||||
- (void)keyDown:(NSEvent *)event {
|
- (void)keyDown:(NSEvent *)event {
|
||||||
if (event.modifierFlags & NSEventModifierFlagCommand) {
|
if (event.modifierFlags & NSEventModifierFlagCommand) {
|
||||||
if ([event.characters isEqualToString:@"w"]) {
|
bool holdShift = event.modifierFlags & NSEventModifierFlagShift;
|
||||||
[self close];
|
@try {
|
||||||
} else if ([event.characters isEqualToString:@"q"]) {
|
unichar key = [event.characters characterAtIndex:0];
|
||||||
[self.appDelegate quitClicked:self];
|
switch (key) {
|
||||||
|
case 'w': [self close]; break;
|
||||||
|
case 'q': [NSApplication.sharedApplication terminate:self]; break;
|
||||||
|
}
|
||||||
|
if (self.window.contentView == self.viewFeeds) { // these only apply for NSOutlineView
|
||||||
|
switch (key) {
|
||||||
|
case 'z':
|
||||||
|
if (holdShift) [self.newsController.managedObjectContext.undoManager redo];
|
||||||
|
else [self.newsController.managedObjectContext.undoManager undo];
|
||||||
|
[self.newsController rearrangeObjects]; // update the ordering
|
||||||
|
break;
|
||||||
|
case 'n': [self.newsController addFeed:nil]; break;
|
||||||
|
case 'o': break; // open .opml file
|
||||||
|
case 's': break; // save data or backup .opml file
|
||||||
|
case 'c': // copy row entry
|
||||||
|
[self.newsController copyDescriptionOfSelectedItems];
|
||||||
|
break;
|
||||||
|
case 'a': [self.feedsOutline selectAll:nil]; break;
|
||||||
|
// TODO: delete
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} @catch (NSException *exception) {
|
||||||
|
NSLog(@"%@", event);
|
||||||
}
|
}
|
||||||
// TODO: new, delete, ...
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
||||||
<plist version="1.0">
|
|
||||||
<dict>
|
|
||||||
<key>com.apple.security.app-sandbox</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.files.user-selected.read-only</key>
|
|
||||||
<true/>
|
|
||||||
<key>com.apple.security.network.client</key>
|
|
||||||
<true/>
|
|
||||||
</dict>
|
|
||||||
</plist>
|
|
||||||
Reference in New Issue
Block a user