Enable Terminal closing with ALT + F4 and warning of multiple open tabs (#2526)

* ALT+F4 to close the terminal app window and warn user of multiple tabs

* Fix indent issue

* Indentation issue fix 2

* add some comments

* move close window warning texts to resources

* CR feedback changes - 8/28

* fix resource file space issue

* Fix resource file space issue 2

* Fix resource file space issue

* minor CR changes

* update comments

* Sync to the latest master branch

* CR changes round 2

* Format fix

* fix type conversion warning

* CR changes on 9-12

* CR feedback changes on 9-12

* add comments why we remove tabs in reverse order

* Fix warnings
This commit is contained in:
Kaiyu Wang 2019-09-16 22:43:27 -07:00 committed by GitHub
parent 2d0608d8c0
commit 5806cdab52
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 139 additions and 40 deletions

View file

@ -167,9 +167,12 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Show a ContentDialog with a single button to dismiss. Uses the
// - Show a ContentDialog with buttons to take further action. Uses the
// FrameworkElements provided as the title and content of this dialog, and
// displays a single button to dismiss.
// displays buttons (or a single button). Two buttons (primary and secondary)
// will be displayed if this is an warning dialog for closing the termimal,
// this allows the users to abondon the closing action. Otherwise, a single
// close button will be displayed.
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens.
// Arguments:

View file

@ -60,6 +60,13 @@ namespace winrt::TerminalApp::implementation
args.Handled(true);
}
void TerminalPage::_HandleCloseWindow(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{
_CloseWindow();
args.Handled(true);
}
void TerminalPage::_HandleScrollUp(const IInspectable& /*sender*/,
const TerminalApp::ActionEventArgs& args)
{

View file

@ -1,17 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
@ -26,36 +26,36 @@
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
@ -193,4 +193,13 @@ Temporarily using the Windows Terminal default settings.
<data name="SettingsMenuItem" xml:space="preserve">
<value>Settings</value>
</data>
</root>
<data name="Cancel" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="CloseAll" xml:space="preserve">
<value>Close all</value>
</data>
<data name="CloseWindowWarningTitle" xml:space="preserve">
<value>Do you want to close all tabs?</value>
</data>
</root>

View file

@ -184,6 +184,29 @@ namespace winrt::TerminalApp::implementation
_showDialogHandlers(*this, dialog);
}
// Method Description:
// - Displays a dialog for warnings found while closing the terminal app using
// key binding with multiple tabs opened. Display messages to warn user
// that more than 1 tab is opend, and once the user clicks the OK button, remove
// all the tabs and shut down and app. If cancel is clicked, the dialog will close
// - Only one dialog can be visible at a time. If another dialog is visible
// when this is called, nothing happens. See _ShowDialog for details
void TerminalPage::_ShowCloseWarningDialog()
{
auto title = _resourceLoader->GetLocalizedString(L"CloseWindowWarningTitle");
auto primaryButtonText = _resourceLoader->GetLocalizedString(L"CloseAll");
auto secondaryButtonText = _resourceLoader->GetLocalizedString(L"Cancel");
Controls::ContentDialog dialog;
dialog.Title(winrt::box_value(title));
dialog.PrimaryButtonText(primaryButtonText);
dialog.SecondaryButtonText(secondaryButtonText);
auto token = dialog.PrimaryButtonClick({ this, &TerminalPage::_CloseWarningPrimaryButtonOnClick });
_showDialogHandlers(*this, dialog);
}
// Method Description:
// - Builds the flyout (dropdown) attached to the new tab button, and
// attaches it to the button. Populates the flyout with one entry per
@ -513,6 +536,7 @@ namespace winrt::TerminalApp::implementation
bindings.DuplicateTab({ this, &TerminalPage::_HandleDuplicateTab });
bindings.CloseTab({ this, &TerminalPage::_HandleCloseTab });
bindings.ClosePane({ this, &TerminalPage::_HandleClosePane });
bindings.CloseWindow({ this, &TerminalPage::_HandleCloseWindow });
bindings.ScrollUp({ this, &TerminalPage::_HandleScrollUp });
bindings.ScrollDown({ this, &TerminalPage::_HandleScrollDown });
bindings.NextTab({ this, &TerminalPage::_HandleNextTab });
@ -603,25 +627,36 @@ namespace winrt::TerminalApp::implementation
}
// Method Description:
// - Removes the tab (both TerminalControl and XAML)
// - Look for the index of the input tabView in the tabs vector,
// and call _RemoveTabViewItemByIndex
// Arguments:
// - tabViewItem: the TabViewItem in the TabView that is being removed.
void TerminalPage::_RemoveTabViewItem(const IInspectable& tabViewItem)
{
uint32_t tabIndexFromControl = 0;
_tabView.Items().IndexOf(tabViewItem, tabIndexFromControl);
_RemoveTabViewItemByIndex(tabIndexFromControl);
}
// Method Description:
// - Removes the tab (both TerminalControl and XAML)
// Arguments:
// - tabIndex: the index of the tab to be removed
void TerminalPage::_RemoveTabViewItemByIndex(uint32_t tabIndex)
{
// To close the window here, we need to close the hosting window.
if (_tabs.size() == 1)
{
_lastTabClosedHandlers(*this, nullptr);
}
uint32_t tabIndexFromControl = 0;
_tabView.Items().IndexOf(tabViewItem, tabIndexFromControl);
auto focusedTabIndex = _GetFocusedTabIndex();
// Removing the tab from the collection will destroy its control and disconnect its connection.
_tabs.erase(_tabs.begin() + tabIndexFromControl);
_tabView.Items().RemoveAt(tabIndexFromControl);
_tabs.erase(_tabs.begin() + tabIndex);
_tabView.Items().RemoveAt(tabIndex);
if (tabIndexFromControl == focusedTabIndex)
auto focusedTabIndex = _GetFocusedTabIndex();
if (tabIndex == focusedTabIndex)
{
auto const tabCount = gsl::narrow_cast<decltype(focusedTabIndex)>(_tabs.size());
if (focusedTabIndex >= tabCount)
@ -771,9 +806,8 @@ namespace winrt::TerminalApp::implementation
// - Close the currently focused tab. Focus will move to the left, if possible.
void TerminalPage::_CloseFocusedTab()
{
int focusedTabIndex = _GetFocusedTabIndex();
std::shared_ptr<Tab> focusedTab{ _tabs[focusedTabIndex] };
_RemoveTabViewItem(focusedTab->GetTabViewItem());
uint32_t focusedTabIndex = _GetFocusedTabIndex();
_RemoveTabViewItemByIndex(focusedTabIndex);
}
// Method Description:
@ -787,6 +821,32 @@ namespace winrt::TerminalApp::implementation
focusedTab->ClosePane();
}
// Method Description:
// - Close the terminal app with keys. If there is more
// than one tab opened, show a warning dialog.
void TerminalPage::_CloseWindow()
{
if (_tabs.size() > 1)
{
_ShowCloseWarningDialog();
}
else
{
_CloseAllTabs();
}
}
// Method Description:
// - Remove all the tabs opened and the terminal will terminate
// on its own when the last tab is closed.
void TerminalPage::_CloseAllTabs()
{
while (!_tabs.empty())
{
_RemoveTabViewItemByIndex(0);
}
}
// Method Description:
// - Move the viewport of the terminal of the currently focused tab up or
// down a number of lines. Negative values of `delta` will move the
@ -1205,6 +1265,20 @@ namespace winrt::TerminalApp::implementation
eventArgs.Cancel(true);
}
// Method Description:
// - Called when the primary button of the content dialog is clicked.
// This calls _CloseAllTabs(), which closes all the tabs currently
// opened and then the Terminal app. This method will be called if
// the user confirms to close all the tabs.
// Arguments:
// - sender: unused
// - ContentDialogButtonClickEventArgs: unused
void TerminalPage::_CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog /* sender */,
Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs /* eventArgs*/)
{
_CloseAllTabs();
}
// Method Description:
// - Hook up keybindings, and refresh the UI of the terminal.
// This includes update the settings of all the tabs according

View file

@ -61,6 +61,7 @@ namespace winrt::TerminalApp::implementation
std::shared_ptr<ScopedResourceLoader> _resourceLoader{ nullptr };
void _ShowAboutDialog();
void _ShowCloseWarningDialog();
void _CreateNewTabFlyout();
void _OpenNewTabDropdown();
@ -71,6 +72,7 @@ namespace winrt::TerminalApp::implementation
void _SettingsButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _FeedbackButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _AboutButtonOnClick(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
void _CloseWarningPrimaryButtonOnClick(Windows::UI::Xaml::Controls::ContentDialog sender, Windows::UI::Xaml::Controls::ContentDialogButtonClickEventArgs eventArgs);
void _HookupKeyBindings(TerminalApp::AppKeyBindings bindings) noexcept;
@ -79,6 +81,7 @@ namespace winrt::TerminalApp::implementation
void _UpdateTabView();
void _DuplicateTabViewItem();
void _RemoveTabViewItem(const IInspectable& tabViewItem);
void _RemoveTabViewItemByIndex(uint32_t tabIndex);
void _RegisterTerminalEvents(Microsoft::Terminal::TerminalControl::TermControl term, std::shared_ptr<Tab> hostingTab);
@ -91,6 +94,8 @@ namespace winrt::TerminalApp::implementation
void _SetFocusedTabIndex(int tabIndex);
void _CloseFocusedTab();
void _CloseFocusedPane();
void _CloseWindow();
void _CloseAllTabs();
// Todo: add more event implementations here
// MSFT:20641986: Add keybindings for New Window
@ -142,6 +147,7 @@ namespace winrt::TerminalApp::implementation
void _HandleResizePane(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleMoveFocus(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleCopyText(const IInspectable& sender, const TerminalApp::ActionEventArgs& args);
void _HandleCloseWindow(const IInspectable&, const TerminalApp::ActionEventArgs& args);
#pragma endregion
};
}