Introduce duplicate tab menu (#9388)

## PR Checklist
* [x] Closes https://github.com/microsoft/terminal/issues/9373
* [x] CLA signed. 
* [ ] Tests added/passed
* [ ] Documentation updated. 
* [ ] Schema updated.
* [ ] I've discussed this with core contributors already.
This commit is contained in:
Don-Vito 2021-03-08 14:16:56 +02:00 committed by GitHub
parent 1202f89399
commit 629c06d0ad
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 36 deletions

View file

@ -330,7 +330,7 @@ namespace TerminalAppLocalTests
{
// * Create a tab with a profile with GUID 1
// * Reload the settings so that GUID 1 is no longer in the list of profiles
// * Try calling _DuplicateTabViewItem on tab 1
// * Try calling _DuplicateFocusedTab on tab 1
// * No new tab should be created (and more importantly, the app should not crash)
//
// Created to test GH#2455
@ -392,7 +392,7 @@ namespace TerminalAppLocalTests
Log::Comment(L"Duplicate the first tab");
result = RunOnUIThread([&page]() {
page->_DuplicateTabViewItem();
page->_DuplicateFocusedTab();
VERIFY_ARE_EQUAL(2u, page->_tabs.Size());
});
VERIFY_SUCCEEDED(result);
@ -407,7 +407,7 @@ namespace TerminalAppLocalTests
Log::Comment(L"Duplicate the tab, and don't crash");
result = RunOnUIThread([&page]() {
page->_DuplicateTabViewItem();
page->_DuplicateFocusedTab();
VERIFY_ARE_EQUAL(2u, page->_tabs.Size(), L"We should gracefully do nothing here - the profile no longer exists.");
});
VERIFY_SUCCEEDED(result);

View file

@ -39,7 +39,7 @@ namespace winrt::TerminalApp::implementation
void TerminalPage::_HandleDuplicateTab(const IInspectable& /*sender*/,
const ActionEventArgs& args)
{
_DuplicateTabViewItem();
_DuplicateFocusedTab();
args.Handled(true);
}

View file

@ -211,6 +211,9 @@
<data name="RenameTabText" xml:space="preserve">
<value>Rename Tab</value>
</data>
<data name="DuplicateTabText" xml:space="preserve">
<value>Duplicate Tab</value>
</data>
<data name="InvalidBackgroundImage" xml:space="preserve">
<value>Found a profile with an invalid "backgroundImage". Defaulting that profile to have no background image. Make sure that when setting a "backgroundImage", the value is a valid file path to an image.</value>
<comment>{Locked="\"backgroundImage\""}</comment>

View file

@ -847,6 +847,16 @@ namespace winrt::TerminalApp::implementation
}
});
newTabImpl->DuplicateRequested([weakTab, weakThis{ get_weak() }]() {
auto page{ weakThis.get() };
auto tab{ weakTab.get() };
if (page && tab)
{
page->_DuplicateTab(*tab);
}
});
auto tabViewItem = newTabImpl->TabViewItem();
_tabView.TabItems().Append(tabViewItem);
@ -1228,43 +1238,52 @@ namespace winrt::TerminalApp::implementation
// Method Description:
// - Duplicates the current focused tab
void TerminalPage::_DuplicateTabViewItem()
void TerminalPage::_DuplicateFocusedTab()
{
if (const auto terminalTab{ _GetFocusedTabImpl() })
{
try
{
// TODO: GH#5047 - In the future, we should get the Profile of
// the focused pane, and use that to build a new instance of the
// settings so we can duplicate this tab/pane.
//
// Currently, if the profile doesn't exist anymore in our
// settings, we'll silently do nothing.
//
// In the future, it will be preferable to just duplicate the
// current control's settings, but we can't do that currently,
// because we won't be able to create a new instance of the
// connection without keeping an instance of the original Profile
// object around.
const auto& profileGuid = terminalTab->GetFocusedProfile();
if (profileGuid.has_value())
{
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
const auto workingDirectory = terminalTab->GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
settings.StartingDirectory(workingDirectory);
}
_CreateNewTabFromSettings(profileGuid.value(), settings);
}
}
CATCH_LOG();
_DuplicateTab(*terminalTab);
}
}
// Method Description:
// - Duplicates specified tab
// Arguments:
// - tab: tab to duplicate
void TerminalPage::_DuplicateTab(const TerminalTab& tab)
{
try
{
// TODO: GH#5047 - In the future, we should get the Profile of
// the focused pane, and use that to build a new instance of the
// settings so we can duplicate this tab/pane.
//
// Currently, if the profile doesn't exist anymore in our
// settings, we'll silently do nothing.
//
// In the future, it will be preferable to just duplicate the
// current control's settings, but we can't do that currently,
// because we won't be able to create a new instance of the
// connection without keeping an instance of the original Profile
// object around.
const auto& profileGuid = tab.GetFocusedProfile();
if (profileGuid.has_value())
{
const auto settings{ winrt::make<TerminalSettings>(_settings, profileGuid.value(), *_bindings) };
const auto workingDirectory = tab.GetActiveTerminalControl().WorkingDirectory();
const auto validWorkingDirectory = !workingDirectory.empty();
if (validWorkingDirectory)
{
settings.StartingDirectory(workingDirectory);
}
_CreateNewTabFromSettings(profileGuid.value(), settings);
}
}
CATCH_LOG();
}
// Method Description:
// - Look for the index of the input tabView in the tabs vector,
// and call _RemoveTab

View file

@ -176,7 +176,8 @@ namespace winrt::TerminalApp::implementation
Windows::Foundation::Collections::IVectorView<Microsoft::Terminal::Settings::Model::Profile> profiles,
Windows::Foundation::Collections::IMapView<winrt::hstring, Microsoft::Terminal::Settings::Model::ColorScheme> schemes);
void _DuplicateTabViewItem();
void _DuplicateFocusedTab();
void _DuplicateTab(const TerminalTab& tab);
void _RemoveTabViewItem(const Microsoft::UI::Xaml::Controls::TabViewItem& tabViewItem);
winrt::Windows::Foundation::IAsyncAction _RemoveTab(winrt::TerminalApp::TabBase tab);
winrt::fire_and_forget _RemoveTabs(const std::vector<winrt::TerminalApp::TabBase> tabs);

View file

@ -841,11 +841,29 @@ namespace winrt::TerminalApp::implementation
renameTabMenuItem.Icon(renameTabSymbol);
}
Controls::MenuFlyoutItem duplicateTabMenuItem;
{
// "Duplicate Tab"
Controls::FontIcon duplicateTabSymbol;
duplicateTabSymbol.FontFamily(Media::FontFamily{ L"Segoe MDL2 Assets" });
duplicateTabSymbol.Glyph(L"\xF5ED");
duplicateTabMenuItem.Click([weakThis](auto&&, auto&&) {
if (auto tab{ weakThis.get() })
{
tab->_DuplicateRequestedHandlers();
}
});
duplicateTabMenuItem.Text(RS_(L"DuplicateTabText"));
duplicateTabMenuItem.Icon(duplicateTabSymbol);
}
// Build the menu
Controls::MenuFlyout newTabFlyout;
Controls::MenuFlyoutSeparator menuSeparator;
newTabFlyout.Items().Append(chooseColorMenuItem);
newTabFlyout.Items().Append(renameTabMenuItem);
newTabFlyout.Items().Append(duplicateTabMenuItem);
newTabFlyout.Items().Append(menuSeparator);
newTabFlyout.Items().Append(_CreateCloseSubMenu());
newTabFlyout.Items().Append(closeTabMenuItem);
@ -1203,4 +1221,5 @@ namespace winrt::TerminalApp::implementation
DEFINE_EVENT(TerminalTab, ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DEFINE_EVENT(TerminalTab, ColorCleared, _colorCleared, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
DEFINE_EVENT(TerminalTab, DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
}

View file

@ -89,6 +89,7 @@ namespace winrt::TerminalApp::implementation
DECLARE_EVENT(ColorSelected, _colorSelected, winrt::delegate<winrt::Windows::UI::Color>);
DECLARE_EVENT(ColorCleared, _colorCleared, winrt::delegate<>);
DECLARE_EVENT(TabRaiseVisualBell, _TabRaiseVisualBellHandlers, winrt::delegate<>);
DECLARE_EVENT(DuplicateRequested, _DuplicateRequestedHandlers, winrt::delegate<>);
FORWARDED_TYPED_EVENT(TabRenamerDeactivated, winrt::Windows::Foundation::IInspectable, winrt::Windows::Foundation::IInspectable, (&_headerControl), RenameEnded);
private:
@ -143,6 +144,8 @@ namespace winrt::TerminalApp::implementation
void _RecalculateAndApplyReadOnly();
void _DuplicateTab();
friend class ::TerminalAppLocalTests::TabTests;
};
}