tdf#136162 implement applying atk properties to gen menus

Change-Id: I77dbc21910b01524d281869a83d9d12efd419bf6
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/101446
Tested-by: Jenkins
Reviewed-by: Caolán McNamara <caolanm@redhat.com>
diff --git a/accessibility/source/standard/accessiblemenubasecomponent.cxx b/accessibility/source/standard/accessiblemenubasecomponent.cxx
index 3c5cdd5..4dbb71c 100644
--- a/accessibility/source/standard/accessiblemenubasecomponent.cxx
+++ b/accessibility/source/standard/accessiblemenubasecomponent.cxx
@@ -579,6 +579,11 @@ void OAccessibleMenuBaseComponent::ProcessMenuEvent( const VclMenuEvent& rVclMen
            RemoveChild( nItemPos );
        }
        break;
        case VclEventId::MenuAccessibleNameChanged:
        {
            UpdateAccessibleName( nItemPos );
        }
        break;
        case VclEventId::MenuItemTextChanged:
        {
            UpdateAccessibleName( nItemPos );
diff --git a/accessibility/source/standard/accessiblemenuitemcomponent.cxx b/accessibility/source/standard/accessiblemenuitemcomponent.cxx
index c4e0860..951d913e 100644
--- a/accessibility/source/standard/accessiblemenuitemcomponent.cxx
+++ b/accessibility/source/standard/accessiblemenuitemcomponent.cxx
@@ -336,7 +336,7 @@ OUString OAccessibleMenuItemComponent::getAccessibleDescription( )

    OUString sDescription;
    if ( m_pParent )
        sDescription = m_pParent->GetHelpText( m_pParent->GetItemId( m_nItemPos ) );
        sDescription = m_pParent->GetAccessibleDescription( m_pParent->GetItemId( m_nItemPos ) );

    return sDescription;
}
diff --git a/include/vcl/builder.hxx b/include/vcl/builder.hxx
index c15b671..6a642a1 100644
--- a/include/vcl/builder.hxx
+++ b/include/vcl/builder.hxx
@@ -345,8 +345,10 @@ private:
    void        extractStock(const OString &id, stringmap &rMap);
    void        extractMnemonicWidget(const OString &id, stringmap &rMap);

    void        handleChild(vcl::Window *pParent, xmlreader::XmlReader &reader);
    VclPtr<vcl::Window> handleObject(vcl::Window *pParent, xmlreader::XmlReader &reader);
    // either pParent or pAtkProps must be set, pParent for a child of a widget, pAtkProps for
    // collecting the atk info for a GtkMenuItem
    void        handleChild(vcl::Window *pParent, stringmap *pAtkProps, xmlreader::XmlReader &reader);
    VclPtr<vcl::Window> handleObject(vcl::Window *pParent, stringmap *pAtkProps, xmlreader::XmlReader &reader);
    void        handlePacking(vcl::Window *pCurrent, vcl::Window *pParent, xmlreader::XmlReader &reader);
    static std::vector<vcl::EnumContext::Context> handleStyle(xmlreader::XmlReader &reader, int &nPriority);
    static OString getStyleClass(xmlreader::XmlReader &reader);
@@ -363,6 +365,7 @@ private:
                   const OString &rClass,
                   const OString &rID,
                   stringmap &rProps,
                   stringmap &rAtkProps,
                   accelmap &rAccels);

    void        handleMenuChild(Menu *pParent, xmlreader::XmlReader &reader);
diff --git a/include/vcl/menu.hxx b/include/vcl/menu.hxx
index bea9e2a..9522204 100644
--- a/include/vcl/menu.hxx
+++ b/include/vcl/menu.hxx
@@ -372,8 +372,12 @@ public:

    vcl::Window* GetWindow() const { return pWindow; }

    void SetAccessibleName( sal_uInt16 nItemId, const OUString& rStr );
    OUString GetAccessibleName( sal_uInt16 nItemId ) const;

    void SetAccessibleDescription( sal_uInt16 nItemId, const OUString& rStr );
    OUString GetAccessibleDescription( sal_uInt16 nItemId ) const;

    // returns whether the item a position nItemPos is highlighted or not.
    bool IsHighlighted( sal_uInt16 nItemPos ) const;

diff --git a/include/vcl/vclevent.hxx b/include/vcl/vclevent.hxx
index ad24a61..a0a11c6 100644
--- a/include/vcl/vclevent.hxx
+++ b/include/vcl/vclevent.hxx
@@ -67,6 +67,7 @@ enum class VclEventId
    ListboxSelect,
    ListboxTreeFocus,
    ListboxTreeSelect,
    MenuAccessibleNameChanged,
    MenuActivate,
    MenuDeactivate,
    MenuDehighlight,
diff --git a/vcl/source/window/builder.cxx b/vcl/source/window/builder.cxx
index 1b2f0ae..2fd0752 100644
--- a/vcl/source/window/builder.cxx
+++ b/vcl/source/window/builder.cxx
@@ -460,7 +460,7 @@ VclBuilder::VclBuilder(vcl::Window* pParent, const OUString& sUIDir, const OUStr
    {
        xmlreader::XmlReader reader(sUri);

        handleChild(pParent, reader);
        handleChild(pParent, nullptr, reader);
    }
    catch (const css::uno::Exception &rExcept)
    {
@@ -2760,7 +2760,7 @@ bool VclBuilder::sortIntoBestTabTraversalOrder::operator()(const vcl::Window *pA
    return false;
}

void VclBuilder::handleChild(vcl::Window *pParent, xmlreader::XmlReader &reader)
void VclBuilder::handleChild(vcl::Window *pParent, stringmap* pAtkProps, xmlreader::XmlReader &reader)
{
    vcl::Window *pCurrentChild = nullptr;

@@ -2798,7 +2798,7 @@ void VclBuilder::handleChild(vcl::Window *pParent, xmlreader::XmlReader &reader)
        {
            if (name == "object" || name == "placeholder")
            {
                pCurrentChild = handleObject(pParent, reader).get();
                pCurrentChild = handleObject(pParent, pAtkProps, reader).get();

                bool bObjectInserted = pCurrentChild && pParent != pCurrentChild;

@@ -3330,6 +3330,7 @@ void VclBuilder::handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader)
    int nLevel = 1;

    stringmap aProperties;
    stringmap aAtkProperties;
    accelmap aAccelerators;

    if (!sCustomProperty.isEmpty())
@@ -3348,9 +3349,10 @@ void VclBuilder::handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader)
            if (name == "child")
            {
                size_t nChildMenuIdx = m_aMenus.size();
                handleChild(nullptr, reader);
                assert(m_aMenus.size() > nChildMenuIdx && "menu not inserted");
                pSubMenu = dynamic_cast<PopupMenu*>(m_aMenus[nChildMenuIdx].m_pMenu.get());
                handleChild(nullptr, &aAtkProperties, reader);
                bool bSubMenuInserted = m_aMenus.size() > nChildMenuIdx;
                if (bSubMenuInserted)
                    pSubMenu = dynamic_cast<PopupMenu*>(m_aMenus[nChildMenuIdx].m_pMenu.get());
            }
            else
            {
@@ -3371,7 +3373,7 @@ void VclBuilder::handleMenuObject(Menu *pParent, xmlreader::XmlReader &reader)
            break;
    }

    insertMenuObject(pParent, pSubMenu, sClass, sID, aProperties, aAccelerators);
    insertMenuObject(pParent, pSubMenu, sClass, sID, aProperties, aAtkProperties, aAccelerators);
}

void VclBuilder::handleSizeGroup(xmlreader::XmlReader &reader)
@@ -3468,7 +3470,7 @@ namespace
}

void VclBuilder::insertMenuObject(Menu *pParent, PopupMenu *pSubMenu, const OString &rClass, const OString &rID,
    stringmap &rProps, accelmap &rAccels)
    stringmap &rProps, stringmap &rAtkProps, accelmap &rAccels)
{
    sal_uInt16 nOldCount = pParent->GetItemCount();
    sal_uInt16 nNewId = ++m_pParserState->m_nLastMenuItemId;
@@ -3527,6 +3529,19 @@ void VclBuilder::insertMenuObject(Menu *pParent, PopupMenu *pSubMenu, const OStr
                SAL_INFO("vcl.builder", "unhandled property: " << rKey);
        }

        for (auto const& prop : rAtkProps)
        {
            const OString &rKey = prop.first;
            const OUString &rValue = prop.second;

            if (rKey == "AtkObject::accessible-name")
                pParent->SetAccessibleName(nNewId, rValue);
            else if (rKey == "AtkObject::accessible-description")
                pParent->SetAccessibleDescription(nNewId, rValue);
            else
                SAL_INFO("vcl.builder", "unhandled atk property: " << rKey);
        }

        for (auto const& accel : rAccels)
        {
            const OString &rSignal = accel.first;
@@ -3568,7 +3583,7 @@ template<typename T> static bool insertItems(vcl::Window *pWindow, VclBuilder::s
    return true;
}

VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, xmlreader::XmlReader &reader)
VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, stringmap *pAtkProps, xmlreader::XmlReader &reader)
{
    OString sClass;
    OString sID;
@@ -3624,8 +3639,13 @@ VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, xmlreader::Xm
    }
    else if (sClass == "AtkObject")
    {
        assert((pParent || pAtkProps) && "must have one set");
        assert(!(pParent && pAtkProps) && "must not have both");
        auto aAtkProperties = handleAtkObject(reader);
        applyAtkProperties(pParent, aAtkProperties);
        if (pParent)
            applyAtkProperties(pParent, aAtkProperties);
        if (pAtkProps)
            *pAtkProps = aAtkProperties;
        return nullptr;
    }

@@ -3656,7 +3676,7 @@ VclPtr<vcl::Window> VclBuilder::handleObject(vcl::Window *pParent, xmlreader::Xm
                    pCurrentChild = insertObject(pParent, sClass, sID,
                        aProperties, aPangoAttributes, aAtkAttributes);
                }
                handleChild(pCurrentChild, reader);
                handleChild(pCurrentChild, nullptr, reader);
            }
            else if (name == "items")
                aItems = handleItems(reader);
diff --git a/vcl/source/window/menu.cxx b/vcl/source/window/menu.cxx
index 6ffbdd2..f0c462d 100644
--- a/vcl/source/window/menu.cxx
+++ b/vcl/source/window/menu.cxx
@@ -2289,6 +2289,18 @@ tools::Rectangle Menu::GetBoundingRectangle( sal_uInt16 nPos ) const
    return aRet;
}

void Menu::SetAccessibleName( sal_uInt16 nItemId, const OUString& rStr )
{
    size_t nPos;
    MenuItemData* pData = pItemList->GetData( nItemId, nPos );

    if (pData && !rStr.equals(pData->aAccessibleName))
    {
        pData->aAccessibleName = rStr;
        ImplCallEventListeners(VclEventId::MenuAccessibleNameChanged, nPos);
    }
}

OUString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
{
    MenuItemData* pData = pItemList->GetData( nItemId );
@@ -2299,6 +2311,24 @@ OUString Menu::GetAccessibleName( sal_uInt16 nItemId ) const
    return OUString();
}

void Menu::SetAccessibleDescription( sal_uInt16 nItemId, const OUString& rStr )
{
    MenuItemData* pData = pItemList->GetData( nItemId );

    if ( pData )
        pData->aAccessibleDescription = rStr;
}

OUString Menu::GetAccessibleDescription( sal_uInt16 nItemId ) const
{
    MenuItemData* pData = pItemList->GetData( nItemId );

    if (pData && !pData->aAccessibleDescription.isEmpty())
        return pData->aAccessibleDescription;

    return GetHelpText(nItemId);
}

void Menu::GetSystemMenuData( SystemMenuData* pData ) const
{
    Menu* pMenu = const_cast<Menu*>(this);
diff --git a/vcl/source/window/menuitemlist.hxx b/vcl/source/window/menuitemlist.hxx
index 8ca4b41..b2f4ca6 100644
--- a/vcl/source/window/menuitemlist.hxx
+++ b/vcl/source/window/menuitemlist.hxx
@@ -54,6 +54,7 @@ struct MenuItemData
    bool            bHiddenOnGUI;
    Size            aSz;                    // only temporarily valid
    OUString        aAccessibleName;        // accessible name
    OUString        aAccessibleDescription; // accessible description

    std::unique_ptr<SalMenuItem> pSalMenuItem; // access to native menu