uui/inc/strings.hrc | 5 uui/source/passworddlg.cxx | 75 +++++++++++--- uui/source/passworddlg.hxx | 3 uui/uiconfig/ui/password.ui | 229 ++++++++++++++++++++++++++------------------ 4 files changed, 200 insertions(+), 112 deletions(-)
New commits: commit 9bcc5970b7d12d20536669300662e046ea361e29 Author: varshneydevansh <[email protected]> AuthorDate: Sun Feb 25 23:58:12 2024 +0530 Commit: Heiko Tietze <[email protected]> CommitDate: Fri Nov 7 15:41:27 2025 +0100 tdf#132007: Refine password prompt dialog UI and text Refines the password dialog for a cleaner user experience. The main prompt now shows just the filename instead of the full path. A the label clarifies whether a password to "open" or "edit" the file is needed. The OK button is disabled until a password is entered. Change-Id: I1288fc94b81984b32f9ade33bd0cd52aa4439b1d Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163924 Tested-by: Jenkins Reviewed-by: Heiko Tietze <[email protected]> diff --git a/uui/inc/strings.hrc b/uui/inc/strings.hrc index 28c0ccd83ad0..62b06a656abe 100644 --- a/uui/inc/strings.hrc +++ b/uui/inc/strings.hrc @@ -21,12 +21,13 @@ #define NC_(Context, String) TranslateId(Context, u8##String) -#define STR_ENTER_PASSWORD_TO_OPEN NC_("STR_ENTER_PASSWORD_TO_OPEN", "Enter password to open file: ") -#define STR_ENTER_PASSWORD_TO_MODIFY NC_("STR_ENTER_PASSWORD_TO_MODIFY", "Enter password to modify file: ") +#define STR_ENTER_PASSWORD_TO_OPEN NC_("STR_ENTER_PASSWORD_TO_OPEN", "The file ā%sā is password-protected.") #define STR_ENTER_SIMPLE_PASSWORD NC_("STR_ENTER_SIMPLE_PASSWORD", "Enter password: ") #define STR_CONFIRM_SIMPLE_PASSWORD NC_("STR_CONFIRM_SIMPLE_PASSWORD", "Confirm password: ") #define STR_TITLE_CREATE_PASSWORD NC_("STR_TITLE_CREATE_PASSWORD", "Set Password") #define STR_TITLE_ENTER_PASSWORD NC_("STR_TITLE_ENTER_PASSWORD", "Enter Password") +//: %TITLE is the base dialog title, %FILENAME is the document's filename, %PRODUCTNAME is the application name (e.g. "LibreOfficeDev") +#define STR_TITLE_FULL_FORMAT NC_("STR_TITLE_FULL_FORMAT", "%TITLE - %FILENAME - %PRODUCTNAME") #define STR_PASSWORD_MISMATCH NC_("STR_PASSWORD_MISMATCH", "The confirmation password did not match the password. Set the password again by entering the same password in both boxes.") #define STR_ALREADYOPEN_TITLE NC_("STR_ALREADYOPEN_TITLE", "Document in Use") diff --git a/uui/source/passworddlg.cxx b/uui/source/passworddlg.cxx index f027746a6994..b78d30c3e41f 100644 --- a/uui/source/passworddlg.cxx +++ b/uui/source/passworddlg.cxx @@ -20,6 +20,7 @@ #include "passworddlg.hxx" #include <strings.hrc> +#include <comphelper/string.hxx> #include <unotools/resmgr.hxx> #include <unotools/configmgr.hxx> #include <tools/urlobj.hxx> @@ -32,7 +33,7 @@ using namespace ::com::sun::star; PasswordDialog::PasswordDialog(weld::Window* pParent, task::PasswordRequestMode nDialogMode, const std::locale& rResLocale, - const OUString& aDocURL, bool bOpenToModify, bool bIsSimplePasswordRequest) + const OUString& aDocURL, bool bIsPasswordToModify, bool bIsSimplePasswordRequest) : GenericDialogController(pParent, u"uui/ui/password.ui"_ustr, u"PasswordDialog"_ustr) , m_xFTPassword(m_xBuilder->weld_label(u"newpassFT"_ustr)) , m_xEDPassword(m_xBuilder->weld_entry(u"newpassEntry"_ustr)) @@ -42,6 +43,8 @@ PasswordDialog::PasswordDialog(weld::Window* pParent, , nMinLen(1) , aPasswdMismatch(Translate::get(STR_PASSWORD_MISMATCH, rResLocale)) { + // Disable the OK button until something has been entered in the password field + m_xOKBtn->set_sensitive(false); // tdf#115964 we can be launched before the parent has resized to its final size m_xDialog->set_centered_on_parent(true); @@ -60,7 +63,6 @@ PasswordDialog::PasswordDialog(weld::Window* pParent, } // default settings for enter password or reenter passwd... - OUString aTitle(Translate::get(STR_TITLE_ENTER_PASSWORD, rResLocale)); m_xFTConfirmPassword->hide(); m_xEDConfirmPassword->hide(); m_xPass[1]->hide(); @@ -71,47 +73,82 @@ PasswordDialog::PasswordDialog(weld::Window* pParent, // settings for create password if (nDialogMode == task::PasswordRequestMode_PASSWORD_CREATE) { - aTitle = Translate::get(STR_TITLE_CREATE_PASSWORD, rResLocale); - + m_xDialog->set_title(Translate::get(STR_TITLE_CREATE_PASSWORD, rResLocale)); m_xFTConfirmPassword->set_label(Translate::get(STR_CONFIRM_SIMPLE_PASSWORD, rResLocale)); m_xFTConfirmPassword->show(); m_xEDConfirmPassword->show(); m_xFTConfirmPassword->set_sensitive(true); m_xEDConfirmPassword->set_sensitive(true); + m_xPass[1]->show(); } - m_xDialog->set_title(aTitle); + auto xOpenLabel = m_xBuilder->weld_label(u"openPasswordLabel"_ustr); + auto xEditLabel = m_xBuilder->weld_label(u"editPasswordLabel"_ustr); + + xOpenLabel->set_visible(!bIsPasswordToModify); + xEditLabel->set_visible(bIsPasswordToModify); + + OUString aMessage(Translate::get(STR_ENTER_PASSWORD_TO_OPEN, rResLocale)); - TranslateId pStrId = bOpenToModify ? STR_ENTER_PASSWORD_TO_MODIFY : STR_ENTER_PASSWORD_TO_OPEN; - OUString aMessage(Translate::get(pStrId, rResLocale)); INetURLObject url(aDocURL); - // tdf#66553 - add file name to title bar for password managers - OUString aFileName = url.getName(INetURLObject::LAST_SEGMENT, true, + // Append filename and product name to the title for password manager compatibility + OUString sFileName = url.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous); - if (!aFileName.isEmpty()) - aFileName += " - " + utl::ConfigManager::getProductName(); - m_xDialog->set_title(aTitle + " - " + aFileName); + if (!sFileName.isEmpty()) + { + const OUString sFinalTitle = Translate::get(STR_TITLE_FULL_FORMAT, rResLocale) + .replaceAll(u"%TITLE", m_xDialog->get_title()) + .replaceAll(u"%FILENAME", sFileName) + .replaceAll(u"%PRODUCTNAME", utl::ConfigManager::getProductName()); + + m_xDialog->set_title(sFinalTitle); + } + + OUString sTooltipTextToShow = url.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous); - auto aUrl = url.HasError() - ? aDocURL : url.GetMainURL(INetURLObject::DecodeMechanism::Unambiguous); - aMessage += m_xFTPassword->escape_ui_str(aUrl); - m_xFTPassword->set_label(aMessage); + if (!url.HasError() && !sTooltipTextToShow.isEmpty()) + { + OUStringBuffer sFileNameBuffer(sFileName); + OUString sFileNameShort = comphelper::string::truncateToLength(sFileNameBuffer, 50).makeStringAndClear(); + + m_xFTPassword->set_label(aMessage.replaceAll("%s", sFileNameShort)); + m_xFTPassword->set_tooltip_text(sTooltipTextToShow); + } + else + { + m_xFTPassword->set_label(aMessage.replaceAll("%s", aDocURL)); + m_xFTPassword->set_tooltip_text(aDocURL); + } + m_xEDPassword->grab_focus(); if (bIsSimplePasswordRequest) { DBG_ASSERT( aDocURL.isEmpty(), "A simple password request should not have a document URL! Use document password request instead." ); m_xFTPassword->set_label(Translate::get(STR_ENTER_SIMPLE_PASSWORD, rResLocale)); + m_xFTPassword->set_tooltip_text({}); } + // This signal handler enables/disables the OK button based on whether the password entry is empty + m_xEDPassword->connect_changed(LINK(this, PasswordDialog, EnableOKBtn_Impl)); + + EnableOKBtn_Impl(*m_xEDPassword); + m_xOKBtn->connect_clicked(LINK(this, PasswordDialog, OKHdl_Impl)); } +IMPL_LINK_NOARG(PasswordDialog, EnableOKBtn_Impl, weld::Entry&, void) +{ + bool bFirstPasswordHasText = !m_xEDPassword->get_text().isEmpty(); + m_xOKBtn->set_sensitive(bFirstPasswordHasText); +} + IMPL_LINK_NOARG(PasswordDialog, OKHdl_Impl, weld::Button&, void) { bool bEDPasswdValid = m_xEDPassword->get_text().getLength() >= nMinLen; - bool bPasswdMismatch = m_xEDConfirmPassword->get_text() != m_xEDPassword->get_text(); + bool bPasswdMismatch = m_xEDConfirmPassword->get_visible() && (m_xEDConfirmPassword->get_text() != m_xEDPassword->get_text()); + bool bValid = (!m_xEDConfirmPassword->get_visible() && bEDPasswdValid) || (m_xEDConfirmPassword->get_visible() && bEDPasswdValid && !bPasswdMismatch); @@ -121,6 +158,10 @@ IMPL_LINK_NOARG(PasswordDialog, OKHdl_Impl, weld::Button&, void) VclMessageType::Warning, VclButtonsType::Ok, aPasswdMismatch)); xBox->run(); + + m_xEDPassword->set_text({}); + m_xEDConfirmPassword->set_text({}); + m_xEDPassword->grab_focus(); } else if (bValid) m_xDialog->response(RET_OK); diff --git a/uui/source/passworddlg.hxx b/uui/source/passworddlg.hxx index f8a303cf65f4..8e2a1a5cbf5f 100644 --- a/uui/source/passworddlg.hxx +++ b/uui/source/passworddlg.hxx @@ -35,11 +35,12 @@ class PasswordDialog : public weld::GenericDialogController DECL_LINK(OKHdl_Impl, weld::Button&, void); + DECL_LINK(EnableOKBtn_Impl, weld::Entry&, void); DECL_LINK(ShowHdl, weld::Toggleable&, void); public: PasswordDialog(weld::Window* pParent, css::task::PasswordRequestMode nDlgMode, const std::locale& rLocale, const OUString& aDocURL, - bool bOpenToModify, bool bIsSimplePasswordRequest); + bool bIsPasswordToModify, bool bIsSimplePasswordRequest); void SetMinLen( sal_uInt16 nMin ) { nMinLen = nMin; } OUString GetPassword() const { return m_xEDPassword->get_text(); } diff --git a/uui/uiconfig/ui/password.ui b/uui/uiconfig/ui/password.ui index f1a38ef93545..90c683d0cadd 100644 --- a/uui/uiconfig/ui/password.ui +++ b/uui/uiconfig/ui/password.ui @@ -14,8 +14,8 @@ </object> <object class="GtkDialog" id="PasswordDialog"> <property name="can-focus">False</property> - <property name="border-width">6</property> - <property name="title" translatable="yes" context="password|PasswordDialog">Set Password</property> + <property name="border-width">12</property> + <property name="title" translatable="yes" context="password|PasswordDialog">Password Protection</property> <property name="modal">True</property> <property name="window-position">center</property> <property name="default-width">0</property> @@ -84,80 +84,60 @@ </packing> </child> <child> - <!-- n-columns=1 n-rows=4 --> + <!-- n-columns=2 n-rows=3 --> <object class="GtkGrid" id="grid1"> <property name="visible">True</property> <property name="can-focus">False</property> <property name="hexpand">True</property> <property name="row-spacing">6</property> <property name="column-spacing">12</property> - <child> - <object class="GtkLabel" id="confirmpassFT"> - <property name="visible">True</property> - <property name="can-focus">False</property> - <property name="use-underline">True</property> - <property name="xalign">0</property> - </object> - <packing> - <property name="left-attach">0</property> - <property name="top-attach">2</property> - </packing> - </child> + <property name="margin-start">12</property> + <property name="margin-end">12</property> + <property name="margin-top">12</property> + <property name="margin-bottom">12</property> <child> <object class="GtkLabel" id="newpassFT"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="use-underline">True</property> + <property name="margin-bottom">6</property> + <property name="label" translatable="yes" context="password|label">The file "%s" is password-protected.</property> <property name="xalign">0</property> + <property name="width-chars">50</property> + <property name="wrap">True</property> + <property name="wrap-mode">word-char</property> </object> <packing> <property name="left-attach">0</property> <property name="top-attach">0</property> + <property name="width">2</property> </packing> </child> <child> - <object class="GtkBox" id="newpassbox"> + <object class="GtkBox" id="passwordLabelBox"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="hexpand">True</property> + <property name="orientation">vertical</property> + <property name="spacing">0</property> + <property name="valign">center</property> <child> - <object class="GtkEntry" id="newpassEntry"> + <object class="GtkLabel" id="openPasswordLabel"> <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="hexpand">True</property> - <property name="visibility">False</property> - <property name="activates-default">True</property> - <property name="truncate-multiline">True</property> - <child internal-child="accessible"> - <object class="AtkObject" id="newpassEntry-atkobject"> - <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|newpassEntry">Type a password. A password is case sensitive.</property> - </object> - </child> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="password|label">_Enter password:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">newpassEntry</property> + <property name="xalign">0</property> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> </child> <child> - <object class="GtkToggleButton" id="togglebt1"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="image">passimg1</property> - <child internal-child="accessible"> - <object class="AtkObject" id="togglebt1-atkobject"> - <property name="AtkObject::accessible-name" translatable="yes" context="password|togglebt1-atkobject">Show Characters</property> - <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|togglebt1">Show or Hide password characters</property> - </object> - </child> + <object class="GtkLabel" id="editPasswordLabel"> + <property name="visible">False</property> + <property name="can-focus">False</property> + <property name="label" translatable="yes" context="password|label">_Enter password to edit:</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">newpassEntry</property> + <property name="xalign">0</property> </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> </child> </object> <packing> @@ -166,53 +146,117 @@ </packing> </child> <child> - <object class="GtkBox" id="confirmpassbox"> + <object class="GtkBox" id="newpassbox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <child> + <object class="GtkEntry" id="newpassEntry"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="visibility">False</property> + <property name="activates-default">True</property> + <property name="truncate-multiline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="newpassEntry-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|newpassEntry">Type a password. A password is case sensitive.</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="togglebt1"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="image">passimg1</property> + <child internal-child="accessible"> + <object class="AtkObject" id="togglebt1-atkobject"> + <property name="AtkObject::accessible-name" translatable="yes" context="password|togglebt1-atkobject">Show Characters</property> + <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|togglebt1">Show or Hide password characters</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">1</property> + </packing> + </child> + <child> + <object class="GtkLabel" id="confirmpassFT"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="hexpand">True</property> - <child> - <object class="GtkEntry" id="confirmpassEntry"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="hexpand">True</property> - <property name="visibility">False</property> - <property name="activates-default">True</property> - <property name="truncate-multiline">True</property> - <child internal-child="accessible"> - <object class="AtkObject" id="confirmpassEntry-atkobject"> - <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|confirmpassEntry">Re-enter the password.</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkToggleButton" id="togglebt2"> - <property name="visible">True</property> - <property name="can-focus">True</property> - <property name="receives-default">True</property> - <property name="image">passimg2</property> - <child internal-child="accessible"> - <object class="AtkObject" id="togglebt2-atkobject"> - <property name="AtkObject::accessible-name" translatable="yes" context="password|togglebt2-atkobject">Show Characters</property> - <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|togglebt2">Show or Hide password characters</property> - </object> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">1</property> - </packing> - </child> + <property name="label" translatable="yes" context="password|label">Reenter password</property> + <property name="use-underline">True</property> + <property name="mnemonic-widget">confirmpassEntry</property> + <property name="xalign">0</property> </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">3</property> + <property name="top-attach">2</property> + </packing> + </child> + <child> + <object class="GtkBox" id="confirmpassbox"> + <property name="visible">True</property> + <property name="can-focus">False</property> + <property name="hexpand">True</property> + <child> + <object class="GtkEntry" id="confirmpassEntry"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="hexpand">True</property> + <property name="visibility">False</property> + <property name="activates-default">True</property> + <property name="truncate-multiline">True</property> + <child internal-child="accessible"> + <object class="AtkObject" id="confirmpassEntry-atkobject"> + <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|confirmpassEntry">Re-enter the password.</property> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkToggleButton" id="togglebt2"> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">True</property> + <property name="image">passimg2</property> + <child internal-child="accessible"> + <object class="AtkObject" id="togglebt2-atkobject"> + <property name="AtkObject::accessible-name" translatable="yes" context="password|togglebt2-atkobject">Show Characters</property> + <property name="AtkObject::accessible-description" translatable="yes" context="password|extended_tip|togglebt2">Show or Hide password characters</property> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> + </object> + <packing> + <property name="left-attach">1</property> + <property name="top-attach">2</property> </packing> </child> </object> @@ -227,6 +271,7 @@ <action-widgets> <action-widget response="-6">cancel</action-widget> <action-widget response="-11">help</action-widget> + <action-widget response="-5">ok</action-widget> </action-widgets> </object> </interface>
