/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef DISABLE_DYNLOADING #include #endif bool toBool(const OString &rValue) { return (!rValue.isEmpty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1')); } namespace { OUString mapStockToImageResource(const OUString& sType) { if (sType == "gtk-index") return OUString(SV_RESID_BITMAP_INDEX); else if (sType == "gtk-refresh") return OUString(SV_RESID_BITMAP_REFRESH); return OUString(); } SymbolType mapStockToSymbol(const OUString& sType) { SymbolType eRet = SymbolType::DONTKNOW; if (sType == "gtk-media-next") eRet = SymbolType::NEXT; else if (sType == "gtk-media-previous") eRet = SymbolType::PREV; else if (sType == "gtk-media-play") eRet = SymbolType::PLAY; else if (sType == "gtk-media-stop") eRet = SymbolType::STOP; else if (sType == "gtk-goto-first") eRet = SymbolType::FIRST; else if (sType == "gtk-goto-last") eRet = SymbolType::LAST; else if (sType == "gtk-go-back") eRet = SymbolType::ARROW_LEFT; else if (sType == "gtk-go-forward") eRet = SymbolType::ARROW_RIGHT; else if (sType == "gtk-go-up") eRet = SymbolType::ARROW_UP; else if (sType == "gtk-go-down") eRet = SymbolType::ARROW_DOWN; else if (sType == "gtk-missing-image") eRet = SymbolType::IMAGE; else if (sType == "gtk-help") eRet = SymbolType::HELP; else if (sType == "gtk-close") eRet = SymbolType::CLOSE; else if (!mapStockToImageResource(sType).isEmpty()) eRet = SymbolType::IMAGE; return eRet; } void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference& rFrame); } #if defined SAL_LOG_WARN namespace { bool isButtonType(WindowType nType) { return nType == WindowType::PUSHBUTTON || nType == WindowType::OKBUTTON || nType == WindowType::CANCELBUTTON || nType == WindowType::HELPBUTTON || nType == WindowType::IMAGEBUTTON || nType == WindowType::MENUBUTTON || nType == WindowType::MOREBUTTON || nType == WindowType::SPINBUTTON; } } #endif VclBuilder::VclBuilder(vcl::Window *pParent, const OUString& sUIDir, const OUString& sUIFile, const OString& sID, const css::uno::Reference& rFrame) : m_sID(sID) , m_sHelpRoot(OUStringToOString(sUIFile, RTL_TEXTENCODING_UTF8)) , m_pStringReplace(Translate::GetReadStringHook()) , m_pParent(pParent) , m_bToplevelParentFound(false) , m_pParserState(new ParserState) , m_xFrame(rFrame) { m_bToplevelHasDeferredInit = pParent && ((pParent->IsSystemWindow() && static_cast(pParent)->isDeferredInit()) || (pParent->IsDockingWindow() && static_cast(pParent)->isDeferredInit())); m_bToplevelHasDeferredProperties = m_bToplevelHasDeferredInit; sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.'); if (nIdx != -1) m_sHelpRoot = m_sHelpRoot.copy(0, nIdx); m_sHelpRoot = m_sHelpRoot + OString('/'); OUString sUri = sUIDir + sUIFile; try { xmlreader::XmlReader reader(sUri); handleChild(pParent, reader); } catch (const css::uno::Exception &rExcept) { SAL_WARN("vcl.layout", "Unable to read .ui file: " << rExcept); CrashReporter::AddKeyValue("VclBuilderException", "Unable to read .ui file: " + rExcept.Message); throw; } //Set Mnemonic widgets when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aMnemonicWidgetMaps.begin(), aEnd = m_pParserState->m_aMnemonicWidgetMaps.end(); aI != aEnd; ++aI) { FixedText *pOne = get(aI->m_sID); vcl::Window *pOther = get(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pOne || !pOther, "vcl", "missing either source " << aI->m_sID << " or target " << aI->m_sValue << " member of Mnemonic Widget Mapping"); if (pOne && pOther) pOne->set_mnemonic_widget(pOther); } //Set a11y relations when everything has been imported for (AtkMap::iterator aI = m_pParserState->m_aAtkInfo.begin(), aEnd = m_pParserState->m_aAtkInfo.end(); aI != aEnd; ++aI) { vcl::Window *pSource = aI->first; const stringmap &rMap = aI->second; for (stringmap::const_iterator aP = rMap.begin(), aEndP = rMap.end(); aP != aEndP; ++aP) { const OUString &rTarget = aP->second; vcl::Window *pTarget = get(rTarget.toUtf8()); SAL_WARN_IF(!pTarget, "vcl", "missing member of a11y relation: " << rTarget); if (!pTarget) continue; const OString &rType = aP->first; if (rType == "labelled-by") pSource->SetAccessibleRelationLabeledBy(pTarget); else if (rType == "label-for") pSource->SetAccessibleRelationLabelFor(pTarget); else if (rType == "member-of") pSource->SetAccessibleRelationMemberOf(pTarget); else { SAL_INFO("vcl.layout", "unhandled a11y relation :" << rType); } } } //Set radiobutton groups when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aGroupMaps.begin(), aEnd = m_pParserState->m_aGroupMaps.end(); aI != aEnd; ++aI) { RadioButton *pOne = get(aI->m_sID); RadioButton *pOther = get(aI->m_sValue); SAL_WARN_IF(!pOne || !pOther, "vcl", "missing member of radiobutton group"); if (pOne && pOther) pOne->group(*pOther); } //Set ComboBox models when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aModelMaps.begin(), aEnd = m_pParserState->m_aModelMaps.end(); aI != aEnd; ++aI) { ListBox *pTarget = get(aI->m_sID); // pStore may be empty const ListStore *pStore = get_model_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget, "vcl", "missing elements of combobox"); if (pTarget && pStore) mungeModel(*pTarget, *pStore, aI->m_nActiveId); } //Set TextView buffers when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aTextBufferMaps.begin(), aEnd = m_pParserState->m_aTextBufferMaps.end(); aI != aEnd; ++aI) { VclMultiLineEdit *pTarget = get(aI->m_sID); const TextBuffer *pBuffer = get_buffer_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pBuffer, "vcl", "missing elements of textview/textbuffer"); if (pTarget && pBuffer) mungeTextBuffer(*pTarget, *pBuffer); } //Set SpinButton adjustments when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aNumericFormatterAdjustmentMaps.begin(), aEnd = m_pParserState->m_aNumericFormatterAdjustmentMaps.end(); aI != aEnd; ++aI) { NumericFormatter *pTarget = dynamic_cast(get(aI->m_sID)); const Adjustment *pAdjustment = get_adjustment_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget, "vcl", "missing NumericFormatter element of spinbutton/adjustment"); SAL_WARN_IF(!pAdjustment, "vcl", "missing Adjustment element of spinbutton/adjustment"); if (pTarget && pAdjustment) mungeAdjustment(*pTarget, *pAdjustment); } for (std::vector::iterator aI = m_pParserState->m_aTimeFormatterAdjustmentMaps.begin(), aEnd = m_pParserState->m_aTimeFormatterAdjustmentMaps.end(); aI != aEnd; ++aI) { TimeField *pTarget = dynamic_cast(get(aI->m_sID)); const Adjustment *pAdjustment = get_adjustment_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of spinbutton/adjustment"); if (pTarget && pAdjustment) mungeAdjustment(*pTarget, *pAdjustment); } for (std::vector::iterator aI = m_pParserState->m_aDateFormatterAdjustmentMaps.begin(), aEnd = m_pParserState->m_aDateFormatterAdjustmentMaps.end(); aI != aEnd; ++aI) { DateField *pTarget = dynamic_cast(get(aI->m_sID)); const Adjustment *pAdjustment = get_adjustment_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of spinbutton/adjustment"); if (pTarget && pAdjustment) mungeAdjustment(*pTarget, *pAdjustment); } //Set ScrollBar adjustments when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aScrollAdjustmentMaps.begin(), aEnd = m_pParserState->m_aScrollAdjustmentMaps.end(); aI != aEnd; ++aI) { ScrollBar *pTarget = get(aI->m_sID); const Adjustment *pAdjustment = get_adjustment_by_name(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of scrollbar/adjustment"); if (pTarget && pAdjustment) mungeAdjustment(*pTarget, *pAdjustment); } //Set Scale(Slider) adjustments std::vector::iterator aIterator; for (aIterator = m_pParserState->m_aSliderAdjustmentMaps.begin(); aIterator != m_pParserState->m_aSliderAdjustmentMaps.end(); ++aIterator) { Slider* pTarget = dynamic_cast(get(aIterator->m_sID)); const Adjustment* pAdjustment = get_adjustment_by_name(aIterator->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pAdjustment, "vcl", "missing elements of scale(slider)/adjustment"); if (pTarget && pAdjustment) { mungeAdjustment(*pTarget, *pAdjustment); } } //Set size-groups when all widgets have been imported for (std::vector::iterator aI = m_pParserState->m_aSizeGroups.begin(), aEnd = m_pParserState->m_aSizeGroups.end(); aI != aEnd; ++aI) { std::shared_ptr xGroup(std::make_shared()); for (stringmap::iterator aP = aI->m_aProperties.begin(), aEndP = aI->m_aProperties.end(); aP != aEndP; ++aP) { const OString &rKey = aP->first; const OUString &rValue = aP->second; xGroup->set_property(rKey, rValue); } for (std::vector::iterator aW = aI->m_aWidgets.begin(), aEndW = aI->m_aWidgets.end(); aW != aEndW; ++aW) { vcl::Window* pWindow = get(aW->getStr()); pWindow->add_to_size_group(xGroup); } } //Set button images when everything has been imported std::set aImagesToBeRemoved; for (std::vector::iterator aI = m_pParserState->m_aButtonImageWidgetMaps.begin(), aEnd = m_pParserState->m_aButtonImageWidgetMaps.end(); aI != aEnd; ++aI) { PushButton *pTargetButton = nullptr; RadioButton *pTargetRadio = nullptr; Button *pTarget = nullptr; if (!aI->m_bRadio) { pTargetButton = get(aI->m_sID); pTarget = pTargetButton; } else { pTargetRadio = get(aI->m_sID); pTarget = pTargetRadio; } FixedImage *pImage = get(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pImage, "vcl", "missing elements of button/image/stock"); if (!pTarget || !pImage) continue; aImagesToBeRemoved.insert(aI->m_sValue); VclBuilder::StockMap::iterator aFind = m_pParserState->m_aStockMap.find(aI->m_sValue.toUtf8()); if (aFind == m_pParserState->m_aStockMap.end()) { if (!aI->m_bRadio) pTargetButton->SetModeImage(pImage->GetImage()); else pTargetRadio->SetModeRadioImage(pImage->GetImage()); } else { const stockinfo &rImageInfo = aFind->second; SymbolType eType = mapStockToSymbol(rImageInfo.m_sStock); SAL_WARN_IF(eType == SymbolType::DONTKNOW, "vcl", "missing stock image element for button"); if (eType == SymbolType::DONTKNOW) continue; if (!aI->m_bRadio) { pTargetButton->SetSymbol(eType); //fdo#76457 keep symbol images small e.g. tools->customize->menu //but images the right size. Really the PushButton::CalcMinimumSize //and PushButton::ImplDrawPushButton are the better place to handle //this, but its such a train-wreck if (eType != SymbolType::IMAGE) pTargetButton->SetStyle(pTargetButton->GetStyle() | WB_SMALLSTYLE); } else SAL_WARN_IF(eType != SymbolType::IMAGE, "vcl.layout", "inimplemented symbol type for radiobuttons"); if (eType == SymbolType::IMAGE) { Image const aImage(StockImage::Yes, mapStockToImageResource(rImageInfo.m_sStock)); if (!aI->m_bRadio) pTargetButton->SetModeImage(aImage); else pTargetRadio->SetModeRadioImage(aImage); } switch (rImageInfo.m_nSize) { case 1: pTarget->SetSmallSymbol(); break; case 4: break; default: SAL_WARN("vcl.layout", "unsupported image size " << rImageInfo.m_nSize); break; } } } //There may be duplicate use of an Image, so we used a set to collect and //now we can remove them from the tree after their final munge for (std::set::iterator aI = aImagesToBeRemoved.begin(), aEnd = aImagesToBeRemoved.end(); aI != aEnd; ++aI) { delete_by_name(aI->toUtf8()); } //Set button menus when everything has been imported for (std::vector::iterator aI = m_pParserState->m_aButtonMenuMaps.begin(), aEnd = m_pParserState->m_aButtonMenuMaps.end(); aI != aEnd; ++aI) { MenuButton *pTarget = get(aI->m_sID); PopupMenu *pMenu = get_menu(aI->m_sValue.toUtf8()); SAL_WARN_IF(!pTarget || !pMenu, "vcl", "missing elements of button/menu"); if (!pTarget || !pMenu) continue; pTarget->SetPopupMenu(pMenu); } //Remove ScrollWindow parent widgets whose children in vcl implement scrolling //internally. for (auto aI = m_pParserState->m_aRedundantParentWidgets.begin(), aEnd = m_pParserState->m_aRedundantParentWidgets.end(); aI != aEnd; ++aI) { delete_by_window(aI->first); } //fdo#67378 merge the label into the disclosure button for (VclPtr const & pOne : m_pParserState->m_aExpanderWidgets) { vcl::Window *pChild = pOne->get_child(); vcl::Window* pLabel = pOne->GetWindow(GetWindowType::LastChild); if (pLabel && pLabel != pChild && pLabel->GetType() == WindowType::FIXEDTEXT) { FixedText *pLabelWidget = static_cast(pLabel); pOne->set_label(pLabelWidget->GetText()); delete_by_window(pLabel); } } //drop maps, etc. that we don't need again m_pParserState.reset(); SAL_WARN_IF(!m_sID.isEmpty() && (!m_bToplevelParentFound && !get_by_name(m_sID)), "vcl.layout", "Requested top level widget \"" << m_sID << "\" not found in " << sUIFile); #if defined SAL_LOG_WARN if (m_bToplevelParentFound && m_pParent->IsDialog()) { int nButtons = 0; bool bHasDefButton = false; for (std::vector::iterator aI = m_aChildren.begin(), aEnd = m_aChildren.end(); aI != aEnd; ++aI) { if (isButtonType(aI->m_pWindow->GetType())) { ++nButtons; if (aI->m_pWindow->GetStyle() & WB_DEFBUTTON) { bHasDefButton = true; break; } } } SAL_WARN_IF(nButtons && !bHasDefButton, "vcl.layout", "No default button defined in " << sUIFile); } #endif } VclBuilder::~VclBuilder() { disposeBuilder(); } void VclBuilder::disposeBuilder() { for (std::vector::reverse_iterator aI = m_aChildren.rbegin(), aEnd = m_aChildren.rend(); aI != aEnd; ++aI) { aI->m_pWindow.disposeAndClear(); } m_aChildren.clear(); for (std::vector::reverse_iterator aI = m_aMenus.rbegin(), aEnd = m_aMenus.rend(); aI != aEnd; ++aI) { aI->m_pMenu.disposeAndClear(); } m_aMenus.clear(); m_pParent.clear(); } namespace { bool extractDrawValue(VclBuilder::stringmap& rMap) { bool bDrawValue = true; VclBuilder::stringmap::iterator aFind = rMap.find(OString("draw_value")); if (aFind != rMap.end()) { bDrawValue = toBool(aFind->second); rMap.erase(aFind); } return bDrawValue; } OUString extractValuePos(VclBuilder::stringmap& rMap) { OUString sRet("top"); VclBuilder::stringmap::iterator aFind = rMap.find(OString("value_pos")); if (aFind != rMap.end()) { sRet = aFind->second; rMap.erase(aFind); } return sRet; } OUString extractTypeHint(VclBuilder::stringmap &rMap) { OUString sRet("normal"); VclBuilder::stringmap::iterator aFind = rMap.find(OString("type-hint")); if (aFind != rMap.end()) { sRet = aFind->second; rMap.erase(aFind); } return sRet; } bool extractResizable(VclBuilder::stringmap &rMap) { bool bResizable = true; VclBuilder::stringmap::iterator aFind = rMap.find(OString("resizable")); if (aFind != rMap.end()) { bResizable = toBool(aFind->second); rMap.erase(aFind); } return bResizable; } bool extractDecorated(VclBuilder::stringmap &rMap) { bool bDecorated = true; VclBuilder::stringmap::iterator aFind = rMap.find(OString("decorated")); if (aFind != rMap.end()) { bDecorated = toBool(aFind->second); rMap.erase(aFind); } return bDecorated; } bool extractCloseable(VclBuilder::stringmap &rMap) { bool bCloseable = true; VclBuilder::stringmap::iterator aFind = rMap.find(OString("deletable")); if (aFind != rMap.end()) { bCloseable = toBool(aFind->second); rMap.erase(aFind); } return bCloseable; } bool extractEntry(VclBuilder::stringmap &rMap) { bool bHasEntry = false; VclBuilder::stringmap::iterator aFind = rMap.find(OString("has-entry")); if (aFind != rMap.end()) { bHasEntry = toBool(aFind->second); rMap.erase(aFind); } return bHasEntry; } bool extractOrientation(VclBuilder::stringmap &rMap) { bool bVertical = false; VclBuilder::stringmap::iterator aFind = rMap.find(OString("orientation")); if (aFind != rMap.end()) { bVertical = aFind->second.equalsIgnoreAsciiCase("vertical"); rMap.erase(aFind); } return bVertical; } bool extractInconsistent(VclBuilder::stringmap &rMap) { bool bInconsistent = false; VclBuilder::stringmap::iterator aFind = rMap.find(OString("inconsistent")); if (aFind != rMap.end()) { bInconsistent = toBool(aFind->second); rMap.erase(aFind); } return bInconsistent; } OUString extractIconName(VclBuilder::stringmap &rMap) { OUString sIconName; VclBuilder::stringmap::iterator aFind = rMap.find(OString("icon-name")); if (aFind != rMap.end()) { sIconName = aFind->second; rMap.erase(aFind); } return sIconName; } OUString getStockText(const OUString &rType) { if (rType == "gtk-ok") return VclResId(SV_BUTTONTEXT_OK); else if (rType == "gtk-cancel") return VclResId(SV_BUTTONTEXT_CANCEL); else if (rType == "gtk-help") return VclResId(SV_BUTTONTEXT_HELP); else if (rType == "gtk-close") return VclResId(SV_BUTTONTEXT_CLOSE); else if (rType == "gtk-revert-to-saved") return VclResId(SV_BUTTONTEXT_RESET); else if (rType == "gtk-add") return VclResId(SV_BUTTONTEXT_ADD); else if (rType == "gtk-delete") return VclResId(SV_BUTTONTEXT_DELETE); else if (rType == "gtk-remove") return VclResId(SV_BUTTONTEXT_REMOVE); else if (rType == "gtk-new") return VclResId(SV_BUTTONTEXT_NEW); else if (rType == "gtk-edit") return VclResId(SV_BUTTONTEXT_EDIT); else if (rType == "gtk-apply") return VclResId(SV_BUTTONTEXT_APPLY); else if (rType == "gtk-save") return VclResId(SV_BUTTONTEXT_SAVE); else if (rType == "gtk-open") return VclResId(SV_BUTTONTEXT_OPEN); else if (rType == "gtk-undo") return VclResId(SV_BUTTONTEXT_UNDO); else if (rType == "gtk-paste") return VclResId(SV_BUTTONTEXT_PASTE); else if (rType == "gtk-media-next") return VclResId(SV_BUTTONTEXT_NEXT); else if (rType == "gtk-media-previous") return VclResId(SV_BUTTONTEXT_PREV); else if (rType == "gtk-go-up") return VclResId(SV_BUTTONTEXT_GO_UP); else if (rType == "gtk-go-down") return VclResId(SV_BUTTONTEXT_GO_DOWN); else if (rType == "gtk-clear") return VclResId(SV_BUTTONTEXT_CLEAR); else if (rType == "gtk-media-play") return VclResId(SV_BUTTONTEXT_PLAY); else if (rType == "gtk-find") return VclResId(SV_BUTTONTEXT_FIND); else if (rType == "gtk-stop") return VclResId(SV_BUTTONTEXT_STOP); else if (rType == "gtk-connect") return VclResId(SV_BUTTONTEXT_CONNECT); else if (rType == "gtk-yes") return VclResId(SV_BUTTONTEXT_YES); else if (rType == "gtk-no") return VclResId(SV_BUTTONTEXT_NO); SAL_WARN("vcl.layout", "unknown stock type: " << rType); return OUString(); } bool extractStock(VclBuilder::stringmap &rMap) { bool bIsStock = false; VclBuilder::stringmap::iterator aFind = rMap.find(OString("use-stock")); if (aFind != rMap.end()) { bIsStock = toBool(aFind->second); rMap.erase(aFind); } return bIsStock; } WinBits extractRelief(VclBuilder::stringmap &rMap) { WinBits nBits = WB_3DLOOK; VclBuilder::stringmap::iterator aFind = rMap.find(OString("relief")); if (aFind != rMap.end()) { if (aFind->second == "half") nBits = WB_FLATBUTTON | WB_BEVELBUTTON; else if (aFind->second == "none") nBits = WB_FLATBUTTON; rMap.erase(aFind); } return nBits; } OUString extractLabel(VclBuilder::stringmap &rMap) { OUString sType; VclBuilder::stringmap::iterator aFind = rMap.find(OString("label")); if (aFind != rMap.end()) { sType = aFind->second; rMap.erase(aFind); } return sType; } OUString extractActionName(VclBuilder::stringmap &rMap) { OUString sActionName; VclBuilder::stringmap::iterator aFind = rMap.find(OString("action-name")); if (aFind != rMap.end()) { sActionName = aFind->second; rMap.erase(aFind); } return sActionName; } bool extractVisible(VclBuilder::stringmap &rMap) { VclBuilder::stringmap::iterator aFind = rMap.find(OString("visible")); if (aFind != rMap.end()) { return toBool(aFind->second); } return false; } Size extractSizeRequest(VclBuilder::stringmap &rMap) { OUString sWidthRequest("0"); OUString sHeightRequest("0"); VclBuilder::stringmap::iterator aFind = rMap.find(OString("width-request")); if (aFind != rMap.end()) { sWidthRequest = aFind->second; rMap.erase(aFind); } aFind = rMap.find(OString("height-request")); if (aFind != rMap.end()) { sHeightRequest = aFind->second; rMap.erase(aFind); } return Size(sWidthRequest.toInt32(), sHeightRequest.toInt32()); } OUString extractTooltipText(VclBuilder::stringmap &rMap) { OUString sTooltipText; VclBuilder::stringmap::iterator aFind = rMap.find(OString("tooltip-text")); if (aFind == rMap.end()) aFind = rMap.find(OString("tooltip-markup")); if (aFind != rMap.end()) { sTooltipText = aFind->second; rMap.erase(aFind); } return sTooltipText; } void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference& rFrame) { if (!rFrame.is()) return; OUString aCommand(extractActionName(rMap)); if (aCommand.isEmpty()) return; OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame)); OUString aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aCommand, aModuleName)); if (!aLabel.isEmpty()) pButton->SetText(aLabel); OUString aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand, rFrame)); if (!aTooltip.isEmpty()) pButton->SetQuickHelpText(aTooltip); Image aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand, rFrame)); pButton->SetModeImage(aImage); pButton->SetCommandHandler(aCommand); } VclPtr