From 2c307cabce528b1c899ca30b2c21a9ae259bc19d Mon Sep 17 00:00:00 2001 From: Allan Odgaard Date: Sat, 20 Jul 2013 00:06:31 +0200 Subject: [PATCH] =?UTF-8?q?Allow=20setting=20a=20tab=20as=20=E2=80=9Cstick?= =?UTF-8?q?y=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Presently this can only be done by right-clicking the tab and selecting the “Sticky” option — if a tab is sticky then it will not be closed when executing any of the batch close actions (Close All Tabs, Close Other Tabs, Close Tabs to the Right, and holding option down while opening a file via file browser or file chooser). Closes #1038. --- .../DocumentWindow/src/DocumentController.mm | 66 ++++++++++++++----- Frameworks/document/src/document.h | 4 ++ 2 files changed, 52 insertions(+), 18 deletions(-) diff --git a/Frameworks/DocumentWindow/src/DocumentController.mm b/Frameworks/DocumentWindow/src/DocumentController.mm index b4650c67..c07cb0c3 100644 --- a/Frameworks/DocumentWindow/src/DocumentController.mm +++ b/Frameworks/DocumentWindow/src/DocumentController.mm @@ -544,7 +544,7 @@ namespace NSMutableIndexSet* allTabs = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, _documents.size())]; for(size_t i = 0; i < _documents.size(); ++i) { - if(_documents[i]->is_modified() && _documents[i]->path() == NULL_STR) + if(_documents[i]->is_modified() && _documents[i]->path() == NULL_STR || _documents[i]->sticky()) [allTabs removeIndex:i]; } [self closeTabsAtIndexes:allTabs askToSaveChanges:YES createDocumentIfEmpty:YES]; @@ -557,7 +557,7 @@ namespace NSMutableIndexSet* otherTabs = [NSMutableIndexSet indexSet]; for(size_t i = 0; i < _documents.size(); ++i) { - if(i != tabIndex && (!_documents[i]->is_modified() || _documents[i]->path() != NULL_STR)) + if(i != tabIndex && (!_documents[i]->is_modified() || _documents[i]->path() != NULL_STR) && !_documents[i]->sticky()) [otherTabs addIndex:i]; } [self closeTabsAtIndexes:otherTabs askToSaveChanges:YES createDocumentIfEmpty:YES]; @@ -793,7 +793,7 @@ namespace for(size_t i = 0; i < newDocuments.size(); ++i) { document::document_ptr doc = newDocuments[i]; - if(!doc->is_modified() && uuids.find(doc->identifier()) == uuids.end()) + if(!doc->is_modified() && uuids.find(doc->identifier()) == uuids.end() && !_documents[i]->sticky()) [indexSet addIndex:i]; } [self closeTabsAtIndexes:indexSet askToSaveChanges:YES createDocumentIfEmpty:NO]; @@ -810,7 +810,7 @@ namespace for(size_t i = 0; i < newDocuments.size(); ++i) { document::document_ptr doc = newDocuments[i]; - if(!doc->is_modified() && doc->is_on_disk() && uuids.find(doc->identifier()) == uuids.end()) + if(!doc->is_modified() && doc->is_on_disk() && uuids.find(doc->identifier()) == uuids.end() && !doc->sticky()) ranked.insert(std::make_pair(doc->lru(), i)); } @@ -1397,6 +1397,16 @@ namespace } } +- (void)toggleSticky:(id)sender +{ + if(NSIndexSet* indexSet = [self tryObtainIndexSetFrom:sender]) + { + std::vector documents; + for(NSUInteger index = [indexSet firstIndex]; index != NSNotFound; index = [indexSet indexGreaterThanIndex:index]) + _documents[index]->set_sticky(!_documents[index]->sticky()); + } +} + - (NSMenu*)menuForTabBarView:(OakTabBarView*)aTabBarView { NSInteger tabIndex = aTabBarView.tag; @@ -1413,28 +1423,32 @@ namespace [rightSideTabs removeIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, tabIndex + 1)]]; } + for(size_t i = 0; i < _documents.size(); ++i) + { + if(_documents[i]->sticky()) + { + [otherTabs removeIndex:i]; + [rightSideTabs removeIndex:i]; + } + } + SEL closeSingleTabSelector = tabIndex == _selectedTabIndex ? @selector(performCloseTab:) : @selector(takeTabsToCloseFrom:); NSMenu* menu = [NSMenu new]; - [menu setAutoenablesItems:NO]; - - [menu addItemWithTitle:@"New Tab" action:@selector(takeNewTabIndexFrom:) keyEquivalent:@""]; - [menu addItem:[NSMenuItem separatorItem]]; - [menu addItemWithTitle:@"Close Tab" action:closeSingleTabSelector keyEquivalent:@""]; - [menu addItemWithTitle:@"Close Other Tabs" action:@selector(takeTabsToCloseFrom:) keyEquivalent:@""]; - [menu addItemWithTitle:@"Close Tabs to the Right" action:@selector(takeTabsToCloseFrom:) keyEquivalent:@""]; - [menu addItem:[NSMenuItem separatorItem]]; + [menu addItemWithTitle:@"New Tab" action:@selector(takeNewTabIndexFrom:) keyEquivalent:@""]; [menu addItemWithTitle:@"Move Tab to New Window" action:@selector(takeTabsToTearOffFrom:) keyEquivalent:@""]; + [menu addItem:[NSMenuItem separatorItem]]; + [menu addItemWithTitle:@"Close Tab" action:closeSingleTabSelector keyEquivalent:@""]; + [menu addItemWithTitle:@"Close Other Tabs" action:@selector(takeTabsToCloseFrom:) keyEquivalent:@""]; + [menu addItemWithTitle:@"Close Tabs to the Right" action:@selector(takeTabsToCloseFrom:) keyEquivalent:@""]; + [menu addItem:[NSMenuItem separatorItem]]; + [menu addItemWithTitle:@"Sticky" action:@selector(toggleSticky:) keyEquivalent:@""]; - NSIndexSet* indexSets[] = { newTabAtTab, nil, clickedTab, otherTabs, rightSideTabs, nil, total > 1 ? clickedTab : [NSIndexSet indexSet] }; + NSIndexSet* indexSets[] = { newTabAtTab, total > 1 ? clickedTab : [NSIndexSet indexSet], nil, clickedTab, otherTabs, rightSideTabs, nil, clickedTab }; for(size_t i = 0; i < sizeofA(indexSets); ++i) { if(NSIndexSet* indexSet = indexSets[i]) - { - if([indexSet count] == 0) - [[menu itemAtIndex:i] setEnabled:NO]; - else [[menu itemAtIndex:i] setRepresentedObject:indexSet]; - } + [[menu itemAtIndex:i] setRepresentedObject:indexSet]; } return menu; @@ -2026,6 +2040,18 @@ namespace [menuItem setTitle:self.window.firstResponder == self.textView ? @"Move Focus to File Browser" : @"Move Focus to Document"]; else if([menuItem action] == @selector(takeProjectPathFrom:)) [menuItem setState:[self.defaultProjectPath isEqualToString:[menuItem representedObject]] ? NSOnState : NSOffState]; + + SEL tabBarActions[] = { @selector(performCloseTab:), @selector(takeNewTabIndexFrom::), @selector(takeTabsToCloseFrom:), @selector(takeTabsToTearOffFrom:), @selector(toggleSticky:) }; + if(oak::contains(std::begin(tabBarActions), std::end(tabBarActions), [menuItem action])) + { + if(NSIndexSet* indexSet = [self tryObtainIndexSetFrom:menuItem]) + { + active = [indexSet count] != 0; + if(active && [menuItem action] == @selector(toggleSticky:)) + [menuItem setState:_documents[[indexSet firstIndex]]->sticky() ? NSOnState : NSOffState]; + } + } + return active; } @@ -2154,6 +2180,8 @@ static NSUInteger DisableSessionSavingCount = 0; doc = path ? document::create(to_s(path)) : create_untitled_document_in_folder(to_s(controller.untitledSavePath)); if(NSString* displayName = info[@"displayName"]) doc->set_custom_name(to_s(displayName)); + if([info[@"sticky"] boolValue]) + doc->set_sticky(true); } doc->set_recent_tracking(false); @@ -2227,6 +2255,8 @@ static NSUInteger DisableSessionSavingCount = 0; doc[@"displayName"] = [NSString stringWithCxxString:document->display_name()]; if(document == controller.selectedDocument) doc[@"selected"] = @YES; + if(document->sticky()) + doc[@"sticky"] = @YES; [docs addObject:doc]; } res[@"documents"] = docs; diff --git a/Frameworks/document/src/document.h b/Frameworks/document/src/document.h index 33bf7b02..653653a3 100644 --- a/Frameworks/document/src/document.h +++ b/Frameworks/document/src/document.h @@ -232,6 +232,9 @@ namespace document bool recent_tracking () const { return _recent_tracking && _path != NULL_STR; } void set_recent_tracking (bool flag) { _recent_tracking = flag; } + bool sticky () const { return _sticky; } + void set_sticky (bool flag) { _sticky = flag; } + ng::buffer_t& buffer () { ASSERT(_buffer); return *_buffer; } ng::buffer_t const& buffer () const { ASSERT(_buffer); return *_buffer; } @@ -293,6 +296,7 @@ namespace document mutable bool _has_lru; bool _is_on_disk; bool _recent_tracking; + bool _sticky = false; mutable std::string _backup_path; // if there is a backup, this is set — we can have a backup even when there is no path mutable ssize_t _backup_revision;