cui/Library_cui.mk                                         |    3 
 cui/source/dialogs/passwdomdlg.cxx                         |  107 +++++++++--
 cui/source/inc/PasswordStrength.hxx                        |   28 ++
 cui/source/inc/passwdomdlg.hxx                             |    3 
 cui/source/util/PasswordStrength.cxx                       |   48 ++++
 cui/uiconfig/ui/password.ui                                |  126 +++++++------
 include/sal/log-areas.dox                                  |    1 
 officecfg/registry/schema/org/openoffice/Office/Common.xcs |   20 ++
 vcl/osx/salnativewidgets.cxx                               |   31 +++
 9 files changed, 301 insertions(+), 66 deletions(-)

New commits:
commit 806656ce4b20aa5b096fe3f072060f6302117afc
Author:     Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>
AuthorDate: Thu Oct 26 14:43:59 2023 +0300
Commit:     Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>
CommitDate: Mon Nov 6 09:04:01 2023 +0100

    tdf#157518: vcl: add native macOS rendering support for LevelBar control
    
    Uses NSLevelIndicator to render LevelBar control on macOS.
    Closely follows the existing implementation for ControlType::Progress
    
    Change-Id: Ibd38e172b8b6297e6322cfe9d5a1b0a6ef0f0656
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158504
    Tested-by: Jenkins
    Reviewed-by: Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>

diff --git a/vcl/osx/salnativewidgets.cxx b/vcl/osx/salnativewidgets.cxx
index 46d13e7473c6..8a7e81fd5d86 100644
--- a/vcl/osx/salnativewidgets.cxx
+++ b/vcl/osx/salnativewidgets.cxx
@@ -194,6 +194,7 @@ bool AquaSalGraphics::isNativeControlSupported(ControlType 
nType, ControlPart nP
                 || nPart == ControlPart::MenuItemRadioMark)
                 return true;
             break;
+        case ControlType::LevelBar:
         case ControlType::Progress:
         case ControlType::IntroProgress:
             if (nPart == ControlPart::Entire)
@@ -611,6 +612,35 @@ bool 
AquaGraphicsBackendBase::performDrawNativeControl(ControlType nType,
                 bOK = true;
             }
             break;
+        case ControlType::LevelBar:
+            {
+                NSRect rect = { NSZeroPoint, NSMakeSize(rc.size.width, 
rc.size.height) };
+                NSLevelIndicator* pBox = [[NSLevelIndicator alloc] 
initWithFrame:rect];
+                [pBox setLevelIndicatorStyle: 
NSLevelIndicatorStyleContinuousCapacity];
+                [pBox setMinValue: 0];
+                [pBox setMaxValue: rc.size.width];
+                [pBox setCriticalValue: rc.size.width * 35.0 / 100.0];
+                [pBox setWarningValue: rc.size.width * 70.0 / 100.0];
+                [pBox setDoubleValue: aValue.getNumericVal()];
+
+                CGContextSaveGState(context);
+                CGContextTranslateCTM(context, rc.origin.x, rc.origin.y);
+
+                NSGraphicsContext* savedContext = [NSGraphicsContext 
currentContext];
+                NSGraphicsContext* graphicsContext = [NSGraphicsContext 
graphicsContextWithCGContext:context flipped:NO];
+                [NSGraphicsContext setCurrentContext: graphicsContext];
+
+                [pBox drawRect: rect];
+
+                [NSGraphicsContext setCurrentContext: savedContext];
+
+                CGContextRestoreGState(context);
+
+                [pBox release];
+
+                bOK = true;
+            }
+            break;
         case ControlType::Progress:
         case ControlType::IntroProgress:
             {
@@ -1104,6 +1134,7 @@ bool AquaSalGraphics::getNativeControlRegion(ControlType 
nType,
                 toReturn = true;
             }
             break;
+        case ControlType::LevelBar:
         case ControlType::Progress:
             {
                 tools::Rectangle aRect(aCtrlBoundRect);
commit b1e24664de424a626f78b9fe002bf4d47c8907d5
Author:     Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>
AuthorDate: Wed Oct 18 15:55:52 2023 +0300
Commit:     Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>
CommitDate: Mon Nov 6 09:03:47 2023 +0100

    tdf#157518: add password policy and strength meter to save with password 
dialog
    
    Introduces new configuration options PasswordPolicy and
    PasswordPolicyErrorMessage.
    
    PasswordPolicy takes a regular expression. When set, it only
    accepts passwords that match that regular expression.
    
    PasswordPolicyErrorMessage is the label displayed when the
    password does not meet the PasswordPolicy.
    In the ideal case, it should contain an explainer of the
    PasswordPolicy, so the user is aware of the requirements.
    
    Save with password dialog had maximum password length enforcing
    bits depending on the requirements of the saved file format.
    These are still applicable in combination with the password
    policy.
    
    Also introduces a visual password meter under the password
    entries. If the password policy isn't satisfied the password
    strength meter is capped at 70%.
    
    The entropy bits to password quality is taken as a linear range.
    Where the range of [0, 112] entropy bits is mapped to percentage
    [0, 100]. Entropy bits ≥ 112 are mapped to 100% since, according
    to KeePass' info page, ≥ 112 entropy bits correspond to a strong
    password: <https://keepass.info/help/kb/pw_quality_est.html>
    
    Change-Id: I2e70adacf271916661219f702dfc217292a1b59f
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158453
    Tested-by: Jenkins
    Reviewed-by: Sarper Akdemir <sarper.akdemir.ext...@allotropia.de>

diff --git a/cui/Library_cui.mk b/cui/Library_cui.mk
index e122d2b734c4..4a41c10baa2c 100644
--- a/cui/Library_cui.mk
+++ b/cui/Library_cui.mk
@@ -71,11 +71,13 @@ $(eval $(call gb_Library_use_externals,cui,\
        boost_headers \
        $(call gb_Helper_optional,OPENCL,\
                clew) \
+       icui18n \
     icuuc \
     icu_headers \
     libxml2 \
     orcus-parser \
     orcus \
+       zxcvbn-c \
     zxing \
 ))
 
@@ -242,6 +244,7 @@ $(eval $(call gb_Library_add_exception_objects,cui,\
     cui/source/tabpages/tptrans \
     cui/source/tabpages/transfrm \
     cui/source/util/FontFeatures \
+    cui/source/util/PasswordStrength \
     cui/source/dialogs/widgettestdlg \
 ))
 
diff --git a/cui/source/dialogs/passwdomdlg.cxx 
b/cui/source/dialogs/passwdomdlg.cxx
index e4981f442fbf..189738b45e3c 100644
--- a/cui/source/dialogs/passwdomdlg.cxx
+++ b/cui/source/dialogs/passwdomdlg.cxx
@@ -19,7 +19,9 @@
 
 #include <sfx2/objsh.hxx>
 #include <vcl/svapp.hxx>
+#include <officecfg/Office/Common.hxx>
 #include <passwdomdlg.hxx>
+#include <PasswordStrength.hxx>
 #include <strings.hrc>
 #include <dialmgr.hxx>
 
@@ -35,8 +37,24 @@ IMPL_LINK_NOARG(PasswordToOpenModifyDialog, OkBtnClickHdl, 
weld::Button&, void)
                                                        m_bIsPasswordToModify? 
m_aInvalidStateForOkButton : m_aInvalidStateForOkButton_v2));
         m_xErrorBox->runAsync(m_xErrorBox, [](sal_Int32 /*nResult*/) {});
     }
-    else // check for mismatched passwords...
+    else // check for mismatched passwords and password policy
     {
+        if (m_oPasswordPolicy)
+        {
+            if 
(!passwordCompliesPolicy(m_xPasswdToOpenED->get_text().toUtf8().getStr()))
+            {
+                m_xPasswdToOpenED->grab_focus();
+                return;
+            }
+
+            if (m_xOpenReadonlyCB->get_active()
+                && 
!passwordCompliesPolicy(m_xPasswdToModifyED->get_text().toUtf8().getStr()))
+            {
+                m_xPasswdToModifyED->grab_focus();
+                return;
+            }
+        }
+
         const bool bToOpenMatch     = m_xPasswdToOpenED->get_text()   == 
m_xReenterPasswdToOpenED->get_text();
         const bool bToModifyMatch   = m_xPasswdToModifyED->get_text() == 
m_xReenterPasswdToModifyED->get_text();
         const int nMismatch = (bToOpenMatch? 0 : 1) + (bToModifyMatch? 0 : 1);
@@ -73,24 +91,56 @@ IMPL_LINK_NOARG(PasswordToOpenModifyDialog, OkBtnClickHdl, 
weld::Button&, void)
 
 IMPL_LINK(PasswordToOpenModifyDialog, ChangeHdl, weld::Entry&, rEntry, void)
 {
+    auto aPasswordText = rEntry.get_text();
+
     weld::Label* pIndicator = nullptr;
-    int nLength = rEntry.get_text().getLength();
+    weld::LevelBar* pLevelBar = nullptr;
     if (&rEntry == m_xPasswdToOpenED.get())
+    {
         pIndicator = m_xPasswdToOpenInd.get();
+        pLevelBar = m_xPasswdToOpenBar.get();
+    }
     else if (&rEntry == m_xReenterPasswdToOpenED.get())
+    {
         pIndicator = m_xReenterPasswdToOpenInd.get();
+    }
     else if (&rEntry == m_xPasswdToModifyED.get())
+    {
         pIndicator = m_xPasswdToModifyInd.get();
+        pLevelBar = m_xPasswdToModifyBar.get();
+    }
     else if (&rEntry == m_xReenterPasswdToModifyED.get())
+    {
         pIndicator = m_xReenterPasswdToModifyInd.get();
+    }
     assert(pIndicator);
-    pIndicator->set_visible(nLength >= m_nMaxPasswdLen);
+
+    bool bPasswordMeetsPolicy = 
passwordCompliesPolicy(aPasswordText.toUtf8().getStr());
+    if (pLevelBar)
+    {
+        rEntry.set_message_type(bPasswordMeetsPolicy ? 
weld::EntryMessageType::Normal
+                                                     : 
weld::EntryMessageType::Error);
+        pIndicator->set_visible(!bPasswordMeetsPolicy);
+    }
+
+    // if password doesn't meet policy cap the percentage at 70%
+    if (pLevelBar)
+        pLevelBar->set_percentage(
+            
std::min(getPasswordStrengthPercentage(aPasswordText.toUtf8().getStr()),
+                     bPasswordMeetsPolicy ? std::numeric_limits<double>::max() 
: 70.0));
+
+    if (m_nMaxPasswdLen)
+    {
+        int nLength = aPasswordText.getLength();
+        pIndicator->set_visible(nLength >= m_nMaxPasswdLen);
+    }
 }
 
 PasswordToOpenModifyDialog::PasswordToOpenModifyDialog(weld::Window * pParent, 
sal_uInt16 nMaxPasswdLen, bool bIsPasswordToModify)
     : SfxDialogController(pParent, "cui/ui/password.ui", "PasswordDialog")
     , m_xPasswdToOpenED(m_xBuilder->weld_entry("newpassEntry"))
     , m_xPasswdToOpenInd(m_xBuilder->weld_label("newpassIndicator"))
+    , m_xPasswdToOpenBar(m_xBuilder->weld_level_bar("passlevelbar"))
     , m_xReenterPasswdToOpenED(m_xBuilder->weld_entry("confirmpassEntry"))
     , m_xReenterPasswdToOpenInd(m_xBuilder->weld_label("confirmpassIndicator"))
     , m_xOptionsExpander(m_xBuilder->weld_expander("expander"))
@@ -99,6 +149,7 @@ 
PasswordToOpenModifyDialog::PasswordToOpenModifyDialog(weld::Window * pParent, s
     , m_xPasswdToModifyFT(m_xBuilder->weld_label("label7"))
     , m_xPasswdToModifyED(m_xBuilder->weld_entry("newpassroEntry"))
     , m_xPasswdToModifyInd(m_xBuilder->weld_label("newpassroIndicator"))
+    , m_xPasswdToModifyBar(m_xBuilder->weld_level_bar("ropasslevelbar"))
     , m_xReenterPasswdToModifyFT(m_xBuilder->weld_label("label8"))
     , m_xReenterPasswdToModifyED(m_xBuilder->weld_entry("confirmropassEntry"))
     , 
m_xReenterPasswdToModifyInd(m_xBuilder->weld_label("confirmropassIndicator"))
@@ -106,27 +157,51 @@ 
PasswordToOpenModifyDialog::PasswordToOpenModifyDialog(weld::Window * pParent, s
     , m_aTwoMismatch( CuiResId( RID_CUISTR_TWO_PASSWORDS_MISMATCH ) )
     , m_aInvalidStateForOkButton( CuiResId( 
RID_CUISTR_INVALID_STATE_FOR_OK_BUTTON ) )
     , m_aInvalidStateForOkButton_v2( CuiResId( 
RID_CUISTR_INVALID_STATE_FOR_OK_BUTTON_V2 ) )
+    , 
m_oPasswordPolicy(officecfg::Office::Common::Security::Scripting::PasswordPolicy::get())
     , m_nMaxPasswdLen(nMaxPasswdLen)
     , m_bIsPasswordToModify( bIsPasswordToModify )
     , m_bAllowEmpty( false )
 {
     m_xOk->connect_clicked(LINK(this, PasswordToOpenModifyDialog, 
OkBtnClickHdl));
-
-    if (nMaxPasswdLen)
+    m_xPasswdToOpenED->connect_changed(LINK(this, PasswordToOpenModifyDialog, 
ChangeHdl));
+    m_xPasswdToModifyED->connect_changed(LINK(this, 
PasswordToOpenModifyDialog, ChangeHdl));
+    if(m_oPasswordPolicy || nMaxPasswdLen)
     {
-        OUString 
aIndicatorTemplate(CuiResId(RID_CUISTR_PASSWORD_LEN_INDICATOR).replaceFirst("%1",
 OUString::number(nMaxPasswdLen)));
-        m_xPasswdToOpenED->set_max_length( nMaxPasswdLen );
-        m_xPasswdToOpenED->connect_changed(LINK(this, 
PasswordToOpenModifyDialog, ChangeHdl));
-        m_xPasswdToOpenInd->set_label(aIndicatorTemplate);
-        m_xReenterPasswdToOpenED->set_max_length( nMaxPasswdLen );
         m_xReenterPasswdToOpenED->connect_changed(LINK(this, 
PasswordToOpenModifyDialog, ChangeHdl));
-        m_xReenterPasswdToOpenInd->set_label(aIndicatorTemplate);
-        m_xPasswdToModifyED->set_max_length( nMaxPasswdLen );
-        m_xPasswdToModifyED->connect_changed(LINK(this, 
PasswordToOpenModifyDialog, ChangeHdl));
-        m_xPasswdToModifyInd->set_label(aIndicatorTemplate);
-        m_xReenterPasswdToModifyED->set_max_length( nMaxPasswdLen );
         m_xReenterPasswdToModifyED->connect_changed(LINK(this, 
PasswordToOpenModifyDialog, ChangeHdl));
-        m_xReenterPasswdToModifyInd->set_label(aIndicatorTemplate);
+
+        OUString aIndicatorText{};
+        OUString aMaxPassLengthIndicator{ 
CuiResId(RID_CUISTR_PASSWORD_LEN_INDICATOR)
+                                              .replaceFirst("%1",
+                                                            
OUString::number(nMaxPasswdLen)) };
+        if (m_oPasswordPolicy && nMaxPasswdLen)
+        {
+            aIndicatorText
+                = 
officecfg::Office::Common::Security::Scripting::PasswordPolicyErrorMessage::get()
+                  + "\n" + aMaxPassLengthIndicator;
+        }
+        else if (m_oPasswordPolicy)
+        {
+            aIndicatorText
+                = 
officecfg::Office::Common::Security::Scripting::PasswordPolicyErrorMessage::get();
+        }
+        else if (nMaxPasswdLen)
+        {
+            aIndicatorText = aMaxPassLengthIndicator;
+        }
+
+        m_xPasswdToOpenInd->set_label(aIndicatorText);
+        m_xReenterPasswdToOpenInd->set_label(aMaxPassLengthIndicator);
+        m_xPasswdToModifyInd->set_label(aIndicatorText);
+        m_xReenterPasswdToModifyInd->set_label(aMaxPassLengthIndicator);
+
+        if (nMaxPasswdLen)
+        {
+            m_xPasswdToOpenED->set_max_length(nMaxPasswdLen);
+            m_xReenterPasswdToOpenED->set_max_length(nMaxPasswdLen);
+            m_xPasswdToModifyED->set_max_length(nMaxPasswdLen);
+            m_xReenterPasswdToModifyED->set_max_length(nMaxPasswdLen);
+        }
     }
 
     m_xPasswdToOpenED->grab_focus();
diff --git a/cui/source/inc/PasswordStrength.hxx 
b/cui/source/inc/PasswordStrength.hxx
new file mode 100644
index 000000000000..e8c9e86a83cb
--- /dev/null
+++ b/cui/source/inc/PasswordStrength.hxx
@@ -0,0 +1,28 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+/** Get password strength percentage
+
+    Maps the received password entropy bits to password strength percentage.
+    0 bits      -> 0%
+    >= 112 bits -> 100%
+
+    @param pPassword null terminated password string.
+    @returns Password strength percentage in the range [0.0, 100.0]
+*/
+double getPasswordStrengthPercentage(const char* pPassword);
+
+/** Checks if the password meets the password policies
+
+    @param pPassword null terminated password string.
+    @returns true if password meets the policy or there is no policy enforced.
+*/
+bool passwordCompliesPolicy(const char* pPassword);
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/cui/source/inc/passwdomdlg.hxx b/cui/source/inc/passwdomdlg.hxx
index 24a1c7b79264..1077195f7a85 100644
--- a/cui/source/inc/passwdomdlg.hxx
+++ b/cui/source/inc/passwdomdlg.hxx
@@ -25,6 +25,7 @@ class PasswordToOpenModifyDialog : public SfxDialogController
 {
     std::unique_ptr<weld::Entry> m_xPasswdToOpenED;
     std::unique_ptr<weld::Label> m_xPasswdToOpenInd;
+    std::unique_ptr<weld::LevelBar> m_xPasswdToOpenBar;
     std::unique_ptr<weld::Entry> m_xReenterPasswdToOpenED;
     std::unique_ptr<weld::Label> m_xReenterPasswdToOpenInd;
     std::unique_ptr<weld::Expander> m_xOptionsExpander;
@@ -33,6 +34,7 @@ class PasswordToOpenModifyDialog : public SfxDialogController
     std::unique_ptr<weld::Label> m_xPasswdToModifyFT;
     std::unique_ptr<weld::Entry> m_xPasswdToModifyED;
     std::unique_ptr<weld::Label> m_xPasswdToModifyInd;
+    std::unique_ptr<weld::LevelBar> m_xPasswdToModifyBar;
     std::unique_ptr<weld::Label> m_xReenterPasswdToModifyFT;
     std::unique_ptr<weld::Entry> m_xReenterPasswdToModifyED;
     std::unique_ptr<weld::Label> m_xReenterPasswdToModifyInd;
@@ -42,6 +44,7 @@ class PasswordToOpenModifyDialog : public SfxDialogController
     OUString                    m_aTwoMismatch;
     OUString                    m_aInvalidStateForOkButton;
     OUString                    m_aInvalidStateForOkButton_v2;
+    std::optional<OUString>     m_oPasswordPolicy;
 
     int                         m_nMaxPasswdLen;
     bool                        m_bIsPasswordToModify;
diff --git a/cui/source/util/PasswordStrength.cxx 
b/cui/source/util/PasswordStrength.cxx
new file mode 100644
index 000000000000..678ad2f74e76
--- /dev/null
+++ b/cui/source/util/PasswordStrength.cxx
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; 
fill-column: 100 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <PasswordStrength.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <unicode/regex.h>
+#include <unicode/unistr.h>
+#include <unicode/errorcode.h>
+#include <sal/log.hxx>
+#include <zxcvbn.h>
+
+double getPasswordStrengthPercentage(const char* pPassword)
+{
+    static constexpr double fMaxStrengthBits = 112.0;
+    return std::min(100.0, ZxcvbnMatch(pPassword, nullptr, nullptr) * 100.0 / 
fMaxStrengthBits);
+}
+
+bool passwordCompliesPolicy(const char* pPassword)
+{
+    std::optional<OUString> oPasswordPolicy
+        = 
officecfg::Office::Common::Security::Scripting::PasswordPolicy::get();
+    if (oPasswordPolicy)
+    {
+        icu::ErrorCode aStatus;
+        icu::UnicodeString sPassword(pPassword);
+        icu::UnicodeString sRegex(oPasswordPolicy->getStr());
+        icu::RegexMatcher aRegexMatcher(sRegex, sPassword, 0, aStatus);
+
+        if (aRegexMatcher.matches(aStatus))
+            return true;
+
+        if (aStatus.isFailure())
+        {
+            SAL_INFO("cui.util", "Password policy regular expression failed 
with error: "
+                                     << aStatus.errorName());
+        }
+        return false;
+    }
+    return true;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s 
cinkeys+=0=break: */
diff --git a/cui/uiconfig/ui/password.ui b/cui/uiconfig/ui/password.ui
index 447968f7fce0..e7bc05e138e4 100644
--- a/cui/uiconfig/ui/password.ui
+++ b/cui/uiconfig/ui/password.ui
@@ -73,7 +73,7 @@
                 <property name="label-xalign">0</property>
                 <property name="shadow-type">none</property>
                 <child>
-                  <!-- n-columns=1 n-rows=6 -->
+                  <!-- n-columns=1 n-rows=7 -->
                   <object class="GtkGrid" id="grid1">
                     <property name="visible">True</property>
                     <property name="can-focus">False</property>
@@ -82,47 +82,6 @@
                     <property name="hexpand">True</property>
                     <property name="row-spacing">6</property>
                     <property name="column-spacing">12</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="width-chars">50</property>
-                        <property name="truncate-multiline">True</property>
-                        <property name="input-purpose">password</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="left-attach">0</property>
-                        <property name="top-attach">1</property>
-                      </packing>
-                    </child>
-                    <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>
-                        <property name="input-purpose">password</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="left-attach">0</property>
-                        <property name="top-attach">3</property>
-                      </packing>
-                    </child>
                     <child>
                       <object class="GtkLabel" id="label1">
                         <property name="visible">True</property>
@@ -134,7 +93,7 @@
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">4</property>
+                        <property name="top-attach">5</property>
                       </packing>
                     </child>
                     <child>
@@ -150,7 +109,7 @@
                             <property name="label-xalign">0</property>
                             <property name="shadow-type">none</property>
                             <child>
-                              <!-- n-columns=1 n-rows=5 -->
+                              <!-- n-columns=1 n-rows=6 -->
                               <object class="GtkGrid" id="grid3">
                                 <property name="visible">True</property>
                                 <property name="can-focus">False</property>
@@ -198,7 +157,7 @@
                                   </object>
                                   <packing>
                                     <property name="left-attach">0</property>
-                                    <property name="top-attach">4</property>
+                                    <property name="top-attach">5</property>
                                   </packing>
                                 </child>
                                 <child>
@@ -206,6 +165,7 @@
                                   <object class="GtkGrid">
                                     <property name="visible">True</property>
                                     <property name="can-focus">False</property>
+                                    <property 
name="column-spacing">12</property>
                                     <child>
                                       <object class="GtkLabel" id="label7">
                                         <property 
name="visible">True</property>
@@ -226,10 +186,11 @@
                                         <property 
name="no-show-all">True</property>
                                         <property name="halign">end</property>
                                         <property 
name="hexpand">True</property>
+                                        <property name="wrap">True</property>
                                         <property name="xalign">0</property>
                                         <child internal-child="accessible">
                                           <object class="AtkObject" 
id="newpassroIndicator-atkobject">
-                                            <property 
name="AtkObject::accessible-role" translatable="no">static</property>
+                                            <property 
name="AtkObject::accessible-role">static</property>
                                           </object>
                                         </child>
                                       </object>
@@ -249,6 +210,7 @@
                                   <object class="GtkGrid">
                                     <property name="visible">True</property>
                                     <property name="can-focus">False</property>
+                                    <property 
name="column-spacing">6</property>
                                     <child>
                                       <object class="GtkLabel" id="label8">
                                         <property 
name="visible">True</property>
@@ -272,7 +234,7 @@
                                         <property name="xalign">0</property>
                                         <child internal-child="accessible">
                                           <object class="AtkObject" 
id="confirmropassIndicator-atkobject">
-                                            <property 
name="AtkObject::accessible-role" translatable="no">static</property>
+                                            <property 
name="AtkObject::accessible-role">static</property>
                                           </object>
                                         </child>
                                       </object>
@@ -282,6 +244,16 @@
                                       </packing>
                                     </child>
                                   </object>
+                                  <packing>
+                                    <property name="left-attach">0</property>
+                                    <property name="top-attach">4</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLevelBar" 
id="ropasslevelbar">
+                                    <property name="visible">True</property>
+                                    <property name="can-focus">False</property>
+                                  </object>
                                   <packing>
                                     <property name="left-attach">0</property>
                                     <property name="top-attach">3</property>
@@ -317,7 +289,7 @@
                       </object>
                       <packing>
                         <property name="left-attach">0</property>
-                        <property name="top-attach">5</property>
+                        <property name="top-attach">6</property>
                       </packing>
                     </child>
                     <child>
@@ -325,6 +297,7 @@
                       <object class="GtkGrid">
                         <property name="visible">True</property>
                         <property name="can-focus">False</property>
+                        <property name="column-spacing">12</property>
                         <child>
                           <object class="GtkLabel" id="label4">
                             <property name="visible">True</property>
@@ -345,10 +318,11 @@
                             <property name="no-show-all">True</property>
                             <property name="halign">end</property>
                             <property name="hexpand">True</property>
+                            <property name="wrap">True</property>
                             <property name="xalign">0</property>
                             <child internal-child="accessible">
                               <object class="AtkObject" 
id="newpassIndicator-atkobject">
-                                <property name="AtkObject::accessible-role" 
translatable="no">static</property>
+                                <property 
name="AtkObject::accessible-role">static</property>
                               </object>
                             </child>
                           </object>
@@ -368,6 +342,7 @@
                       <object class="GtkGrid">
                         <property name="visible">True</property>
                         <property name="can-focus">False</property>
+                        <property name="column-spacing">6</property>
                         <child>
                           <object class="GtkLabel" id="label5">
                             <property name="visible">True</property>
@@ -391,7 +366,7 @@
                             <property name="xalign">0</property>
                             <child internal-child="accessible">
                               <object class="AtkObject" 
id="confirmpassIndicator-atkobject">
-                                <property name="AtkObject::accessible-role" 
translatable="no">static</property>
+                                <property 
name="AtkObject::accessible-role">static</property>
                               </object>
                             </child>
                           </object>
@@ -401,6 +376,57 @@
                           </packing>
                         </child>
                       </object>
+                      <packing>
+                        <property name="left-attach">0</property>
+                        <property name="top-attach">3</property>
+                      </packing>
+                    </child>
+                    <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>
+                        <property name="input-purpose">password</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="left-attach">0</property>
+                        <property name="top-attach">4</property>
+                      </packing>
+                    </child>
+                    <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="width-chars">50</property>
+                        <property name="truncate-multiline">True</property>
+                        <property name="input-purpose">password</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="left-attach">0</property>
+                        <property name="top-attach">1</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkLevelBar" id="passlevelbar">
+                        <property name="visible">True</property>
+                        <property name="can-focus">False</property>
+                      </object>
                       <packing>
                         <property name="left-attach">0</property>
                         <property name="top-attach">2</property>
diff --git a/include/sal/log-areas.dox b/include/sal/log-areas.dox
index 23bbed1a916b..8e6d5d81f1ae 100644
--- a/include/sal/log-areas.dox
+++ b/include/sal/log-areas.dox
@@ -128,6 +128,7 @@ certain functionality.
 @li @c cui.factory
 @li @c cui.options
 @li @c cui.tabpages
+@li @c cui.util
 
 @section drawinglayer
 
diff --git a/officecfg/registry/schema/org/openoffice/Office/Common.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
index fcb8392436a9..76aa4e6c02d9 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Common.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Common.xcs
@@ -2455,6 +2455,26 @@
           </info>
           <value>false</value>
         </prop>
+        <prop oor:name="PasswordPolicy" oor:type="xs:string">
+          <info>
+            <desc>Specifies the password policy regular expression to be forced
+            when a password is being entered. If the password doesn't match the
+            regular expression it is denied.
+
+            For example a policy that enforces minimum eight characters, at
+            least one uppercase, one lowercase letter and one number would be:
+            ^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)[a-zA-Z\d]{8,}$
+            </desc>
+          </info>
+        </prop>
+        <prop oor:name="PasswordPolicyErrorMessage" oor:type="xs:string" 
oor:localized="true" oor:nillable="false">
+          <info>
+            <desc>Specifies the displayed error message when the entered
+            password doesn't meet the password policy. Should describe the
+            password policy.</desc>
+          </info>
+          <value>Password does not meet the password policy.</value>
+        </prop>
         <prop oor:name="HyperlinksWithCtrlClick" oor:type="xs:boolean" 
oor:nillable="false">
           <info>
             <desc>Specifies whether ctrl-click is required to follow

Reply via email to