Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/LibreOffice/vcl/source/window/   (Office von Apache Version 25.8.3.2©)  Datei vom 5.10.2025 mit Größe 137 kB image not shown  

Quelle  builder.cxx   Sprache: C

 
/* -*- 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 <config_feature_desktop.h>
#include <config_options.h>
#include <config_vclplug.h>

#include <memory>
#include <string_view>
#include <com/sun/star/accessibility/AccessibleRole.hpp>

#include <frozen/bits/elsa_std.h>
#include <frozen/unordered_map.h>

#include <comphelper/lok.hxx>
#include <i18nutil/unicode.hxx>
#include <jsdialog/enabled.hxx>
#include <o3tl/string_view.hxx>
#include <officecfg/Office/Common.hxx>
#include <osl/module.hxx>
#include <sal/log.hxx>
#include <unotools/localedatawrapper.hxx>
#include <unotools/resmgr.hxx>
#include <utility>
#include <vcl/builder.hxx>
#include <vcl/dialoghelper.hxx>
#include <vcl/menu.hxx>
#include <vcl/toolkit/button.hxx>
#include <vcl/toolkit/dialog.hxx>
#include <vcl/toolkit/edit.hxx>
#include <vcl/toolkit/field.hxx>
#include <vcl/fieldvalues.hxx>
#include <vcl/toolkit/fmtfield.hxx>
#include <vcl/toolkit/fixed.hxx>
#include <vcl/toolkit/fixedhyper.hxx>
#include <vcl/headbar.hxx>
#include <vcl/notebookbar/NotebookBarAddonsMerger.hxx>
#include <vcl/toolkit/ivctrl.hxx>
#include <vcl/layout.hxx>
#include <vcl/toolkit/lstbox.hxx>
#include <vcl/toolkit/MenuButton.hxx>
#include <vcl/mnemonic.hxx>
#include <vcl/toolkit/prgsbar.hxx>
#include <vcl/toolkit/scrbar.hxx>
#include <vcl/split.hxx>
#include <vcl/svapp.hxx>
#include <vcl/toolkit/svtabbx.hxx>
#include <vcl/tabctrl.hxx>
#include <vcl/tabpage.hxx>
#include <vcl/toolkit/throbber.hxx>
#include <vcl/toolbox.hxx>
#include <vcl/toolkit/treelistentry.hxx>
#include <vcl/toolkit/vclmedit.hxx>
#include <vcl/settings.hxx>
#include <slider.hxx>
#include <vcl/weld.hxx>
#include <vcl/weldutils.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <iconview.hxx>
#include <svdata.hxx>
#include <bitmaps.hlst>
#include <managedmenubutton.hxx>
#include <messagedialog.hxx>
#include <ContextVBox.hxx>
#include <DropdownBox.hxx>
#include <OptionalBox.hxx>
#include <PriorityMergedHBox.hxx>
#include <PriorityHBox.hxx>
#include <window.h>
#include <xmlreader/xmlreader.hxx>
#include <desktop/crashreport.hxx>
#include <calendar.hxx>
#include <menutogglebutton.hxx>
#include <salinst.hxx>
#include <strings.hrc>
#include <treeglue.hxx>
#include <verticaltabctrl.hxx>
#include <wizdlg.hxx>
#include <tools/svlibrary.h>
#include <jsdialog/jsdialogbuilder.hxx>

#if defined(DISABLE_DYNLOADING) || defined(LINUX)
#include <dlfcn.h>
#endif

bool toBool(std::u16string_view rValue)
{
    return (!rValue.empty() && (rValue[0] == 't' || rValue[0] == 'T' || rValue[0] == '1'));
}

namespace
{
    const OUString & mapStockToImageResource(std::u16string_view sType)
    {
        if (sType == u"view-refresh")
            return SV_RESID_BITMAP_REFRESH;
        else if (sType == u"dialog-error")
            return IMG_ERROR;
        else if (sType == u"list-add")
            return IMG_ADD;
        else if (sType == u"list-remove")
            return IMG_REMOVE;
        else if (sType == u"edit-copy")
            return IMG_COPY;
        else if (sType == u"edit-paste")
            return IMG_PASTE;
        else if (sType == u"document-open")
            return IMG_OPEN;
        else if (sType == u"open-menu-symbolic")
            return IMG_MENU;
        else if (sType == u"window-close-symbolic")
            return SV_RESID_BITMAP_CLOSEDOC;
        else if (sType == u"x-office-calendar")
            return IMG_CALENDAR;
        else if (sType == u"accessories-character-map")
            return IMG_CHARACTER_MAP;
        return EMPTY_OUSTRING;
    }

}

SymbolType VclBuilder::mapStockToSymbol(std::u16string_view sType)
{
    SymbolType eRet = SymbolType::DONTKNOW;
    if (sType == u"media-skip-forward")
        eRet = SymbolType::NEXT;
    else if (sType == u"media-skip-backward")
        eRet = SymbolType::PREV;
    else if (sType == u"media-playback-start")
        eRet = SymbolType::PLAY;
    else if (sType == u"media-playback-stop")
        eRet = SymbolType::STOP;
    else if (sType == u"go-first")
        eRet = SymbolType::FIRST;
    else if (sType == u"go-last")
        eRet = SymbolType::LAST;
    else if (sType == u"go-previous")
        eRet = SymbolType::ARROW_LEFT;
    else if (sType == u"go-next")
        eRet = SymbolType::ARROW_RIGHT;
    else if (sType == u"go-up")
        eRet = SymbolType::ARROW_UP;
    else if (sType == u"go-down")
        eRet = SymbolType::ARROW_DOWN;
    else if (sType == u"missing-image")
        eRet = SymbolType::IMAGE;
    else if (sType == u"help-browser" || sType == u"help-browser-symbolic")
        eRet = SymbolType::HELP;
    else if (sType == u"window-close")
        eRet = SymbolType::CLOSE;
    else if (sType == u"document-new")
        eRet = SymbolType::PLUS;
    else if (sType == u"pan-down-symbolic")
        eRet = SymbolType::SPIN_DOWN;
    else if (sType == u"pan-up-symbolic")
        eRet = SymbolType::SPIN_UP;
    else if (!mapStockToImageResource(sType).isEmpty())
        eRet = SymbolType::IMAGE;
    return eRet;
}

namespace
{
    void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference<css::frame::XFrame>& rFrame);

#if defined SAL_LOG_WARN
    bool isButtonType(WindowType eType)
    {
        return eType == WindowType::PUSHBUTTON ||
               eType == WindowType::OKBUTTON ||
               eType == WindowType::CANCELBUTTON ||
               eType == WindowType::HELPBUTTON ||
               eType == WindowType::IMAGEBUTTON ||
               eType == WindowType::MENUBUTTON ||
               eType == WindowType::MOREBUTTON ||
               eType == WindowType::SPINBUTTON;
    }
#endif

}

std::unique_ptr<weld::Builder> Application::CreateBuilder(weld::Widget* pParent, const OUString &rUIFile, bool bMobile, sal_uInt64 nLOKWindowId)
{
    if (comphelper::LibreOfficeKit::isActive() && !jsdialog::isIgnored(rUIFile))
    {
        if (jsdialog::isBuilderEnabledForSidebar(rUIFile))
            return JSInstanceBuilder::CreateSidebarBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, "sidebar", nLOKWindowId);
        else if (jsdialog::isBuilderEnabledForPopup(rUIFile))
            return JSInstanceBuilder::CreatePopupBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile);
        else if (jsdialog::isBuilderEnabledForMenu(rUIFile))
            return JSInstanceBuilder::CreateMenuBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile);
        else if (jsdialog::isBuilderEnabledForNavigator(rUIFile))
            return JSInstanceBuilder::CreateSidebarBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, "navigator", nLOKWindowId);
        else if (jsdialog::isBuilderEnabled(rUIFile, bMobile))
            return JSInstanceBuilder::CreateDialogBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile);
        else
            SAL_WARN("vcl""UI file not enabled for JSDialogs: " << rUIFile);
    }

    return ImplGetSVData()->mpDefInst->CreateBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile);
}

std::unique_ptr<weld::Builder> Application::CreateInterimBuilder(vcl::Window* pParent, const OUString &rUIFile, bool bAllowCycleFocusOut, sal_uInt64 nLOKWindowId)
{
    if (comphelper::LibreOfficeKit::isActive() && !jsdialog::isIgnored(rUIFile))
    {
        // Notebookbar sub controls
        if (jsdialog::isInterimBuilderEnabledForNotebookbar(rUIFile))
            return JSInstanceBuilder::CreateNotebookbarBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, css::uno::Reference<css::frame::XFrame>(), nLOKWindowId);
        else if (jsdialog::isBuilderEnabledForFormulabar(rUIFile))
            return JSInstanceBuilder::CreateFormulabarBuilder(pParent, AllSettings::GetUIRootDir(),
                                                              rUIFile, nLOKWindowId);
        else if (jsdialog::isBuilderEnabledForAddressInput(rUIFile))
            return JSInstanceBuilder::CreateAddressInputBuilder(
                pParent, AllSettings::GetUIRootDir(), rUIFile, nLOKWindowId);
        else
            SAL_WARN("vcl""UI file not enabled for JSDialogs: " << rUIFile);
    }

    return ImplGetSVData()->mpDefInst->CreateInterimBuilder(pParent, AllSettings::GetUIRootDir(), rUIFile, bAllowCycleFocusOut, nLOKWindowId);
}

weld::MessageDialog* Application::CreateMessageDialog(weld::Widget* pParent, VclMessageType eMessageType,
                                                      VclButtonsType eButtonType, const OUString& rPrimaryMessage,
                                                      const ILibreOfficeKitNotifier* pNotifier)
{
    if (comphelper::LibreOfficeKit::isActive())
        return JSInstanceBuilder::CreateMessageDialog(pParent, eMessageType, eButtonType, rPrimaryMessage, pNotifier);
    else
        return ImplGetSVData()->mpDefInst->CreateMessageDialog(pParent, eMessageType, eButtonType, rPrimaryMessage);
}

weld::Window* Application::GetFrameWeld(const css::uno::Reference<css::awt::XWindow>&&nbsp;rWindow)
{
    return ImplGetSVData()->mpDefInst->GetFrameWeld(rWindow);
}

namespace weld
{
    OUString MetricSpinButton::MetricToString(FieldUnit rUnit)
    {
        const FieldUnitStringList& rList = ImplGetFieldUnits();
        // return unit's default string (ie, the first one )
        auto it = std::find_if(
            rList.begin(), rList.end(),
            [&rUnit](const std::pair<OUString, FieldUnit>& rItem) { return rItem.second == rUnit; });
        if (it != rList.end())
            return it->first;

        return OUString();
    }

    IMPL_LINK_NOARG(MetricSpinButton, spin_button_value_changed, SpinButton&, void)
    {
        signal_value_changed();
    }

    IMPL_LINK(MetricSpinButton, spin_button_output, sal_Int64, nValue, OUString)
    {
        return format_number(nValue);
    }

    void MetricSpinButton::update_width_chars()
    {
        sal_Int64 min, max;
        m_xSpinButton->get_range(min, max);
        auto width = std::max(m_xSpinButton->get_pixel_size(format_number(min)).Width(),
                              m_xSpinButton->get_pixel_size(format_number(max)).Width());
        int chars = ceil(width / m_xSpinButton->get_approximate_digit_width());
        m_xSpinButton->set_width_chars(chars);
    }

    unsigned int SpinButton::Power10(unsigned int n)
    {
        unsigned int nValue = 1;
        for (unsigned int i = 0; i < n; ++i)
            nValue *= 10;
        return nValue;
    }

    sal_Int64 SpinButton::denormalize(sal_Int64 nValue) const
    {
        const int nFactor = Power10(get_digits());

        if ((nValue < (std::numeric_limits<sal_Int64>::min() + nFactor)) ||
            (nValue > (std::numeric_limits<sal_Int64>::max() - nFactor)))
        {
            return nValue / nFactor;
        }

        const int nHalf = nFactor / 2;

        if (nValue < 0)
            return (nValue - nHalf) / nFactor;
        return (nValue + nHalf) / nFactor;
    }

    OUString MetricSpinButton::format_number(sal_Int64 nValue) const
    {
        OUString aStr;

        const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();

        unsigned int nDecimalDigits = m_xSpinButton->get_digits();
        //pawn percent off to icu to decide whether percent is separated from its number for this locale
        if (m_eSrcUnit == FieldUnit::PERCENT)
        {
            double fValue = nValue;
            fValue /= SpinButton::Power10(nDecimalDigits);
            aStr = unicode::formatPercent(fValue, rLocaleData.getLanguageTag());
        }
        else
        {
            aStr = rLocaleData.getNum(nValue, nDecimalDigits, truetrue);
            OUString aSuffix = MetricToString(m_eSrcUnit);
            if (m_eSrcUnit != FieldUnit::NONE && m_eSrcUnit != FieldUnit::DEGREE && m_eSrcUnit != FieldUnit::INCH && m_eSrcUnit != FieldUnit::FOOT)
                aStr += " ";
            if (m_eSrcUnit == FieldUnit::INCH)
            {
                OUString sDoublePrime = u"\u2033"_ustr;
                if (aSuffix != "\"" && aSuffix != sDoublePrime)
                    aStr += " ";
                else
                    aSuffix = sDoublePrime;
            }
            else if (m_eSrcUnit == FieldUnit::FOOT)
            {
                OUString sPrime = u"\u2032"_ustr;
                if (aSuffix != "'" && aSuffix != sPrime)
                    aStr += " ";
                else
                    aSuffix = sPrime;
            }

            assert(m_eSrcUnit != FieldUnit::PERCENT);
            aStr += aSuffix;
        }

        return aStr;
    }

    void MetricSpinButton::set_digits(unsigned int digits)
    {
        sal_Int64 step, page;
        get_increments(step, page, m_eSrcUnit);
        sal_Int64 value = get_value(m_eSrcUnit);
        m_xSpinButton->set_digits(digits);
        set_increments(step, page, m_eSrcUnit);
        set_value(value, m_eSrcUnit);
        update_width_chars();
    }

    void MetricSpinButton::set_unit(FieldUnit eUnit)
    {
        if (eUnit != m_eSrcUnit)
        {
            sal_Int64 step, page;
            get_increments(step, page, m_eSrcUnit);
            sal_Int64 value = get_value(m_eSrcUnit);
            m_eSrcUnit = eUnit;
            set_increments(step, page, m_eSrcUnit);
            set_value(value, m_eSrcUnit);
            const OUString sText = format_number(m_xSpinButton->get_value());
            m_xSpinButton->set_text(sText);
            update_width_chars();
        }
    }

    sal_Int64 MetricSpinButton::ConvertValue(sal_Int64 nValue, FieldUnit eInUnit, FieldUnit eOutUnit) const
    {
        return vcl::ConvertValue(nValue, 0, m_xSpinButton->get_digits(), eInUnit, eOutUnit);
    }

    IMPL_LINK(MetricSpinButton, spin_button_input, const OUString&, rText, std::optional<int>)
    {
        const LocaleDataWrapper& rLocaleData = Application::GetSettings().GetLocaleDataWrapper();
        double fResult(0.0);
        bool bRet = vcl::TextToValue(rText, fResult, 0, m_xSpinButton->get_digits(), rLocaleData, m_eSrcUnit);
        if (!bRet)
            return {};

        if (fResult > SAL_MAX_INT32)
            fResult = SAL_MAX_INT32;
        else if (fResult < SAL_MIN_INT32)
            fResult = SAL_MIN_INT32;

        return std::optional<int>(std::round(fResult));
    }

    EntryTreeView::EntryTreeView(std::unique_ptr<Entry> xEntry, std::unique_ptr<TreeView> xTreeView)
        : m_xEntry(std::move(xEntry))
        , m_xTreeView(std::move(xTreeView))
    {
        m_xTreeView->connect_selection_changed(LINK(this, EntryTreeView, ClickHdl));
        m_xEntry->connect_changed(LINK(this, EntryTreeView, ModifyHdl));
    }

    IMPL_LINK(EntryTreeView, ClickHdl, weld::TreeView&, rView, void)
    {
        m_xEntry->set_text(rView.get_selected_text());
        m_aChangeHdl.Call(*this);
    }

    IMPL_LINK_NOARG(EntryTreeView, ModifyHdl, weld::Entry&, void)
    {
        m_aChangeHdl.Call(*this);
    }

    void EntryTreeView::set_height_request_by_rows(int nRows)
    {
        int nHeight = nRows == -1 ? -1 : m_xTreeView->get_height_rows(nRows);
        m_xTreeView->set_size_request(m_xTreeView->get_size_request().Width(), nHeight);
    }

    size_t GetAbsPos(const weld::TreeView& rTreeView, const weld::TreeIter& rIter)
    {
        size_t nAbsPos = 0;

        std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(&rIter));
        if (!rTreeView.get_iter_first(*xEntry))
            xEntry.reset();

        while (xEntry && rTreeView.iter_compare(*xEntry, rIter) != 0)
        {
            if (!rTreeView.iter_next(*xEntry))
                xEntry.reset();
            nAbsPos++;
        }

        return nAbsPos;
    }

    bool IsEntryVisible(const weld::TreeView& rTreeView, const weld::TreeIter& rIter)
    {
        // short circuit for the common case
        if (rTreeView.get_iter_depth(rIter) == 0)
            return true;

        std::unique_ptr<weld::TreeIter> xEntry(rTreeView.make_iterator(&rIter));
        bool bRetVal = false;
        do
        {
            if (rTreeView.get_iter_depth(*xEntry) == 0)
            {
                bRetVal = true;
                break;
            }
        }  while (rTreeView.iter_parent(*xEntry) && rTreeView.get_row_expanded(*xEntry));
        return bRetVal;
    }
}

// static
void BuilderBase::reportException(const css::uno::Exception& rExcept)
{
    CrashReporter::addKeyValue(u"VclBuilderException"_ustr,
                               "Unable to read .ui file: " + rExcept.Message, CrashReporter::Write);
}

BuilderBase::BuilderBase(std::u16string_view sUIDir, const OUString& rUIFile, bool bLegacy)
    : m_pParserState(new ParserState)
    , m_sUIFileUrl(sUIDir + rUIFile)
    , m_sHelpRoot(rUIFile)
    , m_bLegacy(bLegacy)
{
    const sal_Int32 nIdx = m_sHelpRoot.lastIndexOf('.');
    if (nIdx != -1)
        m_sHelpRoot = m_sHelpRoot.copy(0, nIdx);
    m_sHelpRoot += "/";
}

const std::locale& BuilderBase::getResLocale() const
{
    assert(m_pParserState && "parser state no more valid");
    return m_pParserState->m_aResLocale;
}

const std::vector<BuilderBase::SizeGroup>& BuilderBase::getSizeGroups() const
{
    assert(m_pParserState && "parser state no more valid");
    return m_pParserState->m_aSizeGroups;
}

const std::vector<BuilderBase::MnemonicWidgetMap>& BuilderBase::getMnemonicWidgetMaps() const {
    assert(m_pParserState && "parser state no more valid");
    return m_pParserState->m_aMnemonicWidgetMaps;
}

const std::vector<BuilderBase::RadioButtonGroupMap>& BuilderBase::getRadioButtonGroupMaps() const {
    assert(m_pParserState && "parser state no more valid");
    return m_pParserState->m_aRadioButtonGroupMaps;
}

OUString BuilderBase::finalizeValue(const OString& rContext, const OString& rValue,
                                    const bool bTranslate) const
{
    OUString sFinalValue;
    if (bTranslate)
    {
        sFinalValue
            = Translate::get(TranslateId{ rContext.getStr(), rValue.getStr() }, getResLocale());
    }
    else
        sFinalValue = OUString::fromUtf8(rValue);

    if (ResHookProc pStringReplace = Translate::GetReadStringHook())
        sFinalValue = (*pStringReplace)(sFinalValue);

    return sFinalValue;
}

void BuilderBase::resetParserState() { m_pParserState.reset(); }

VclBuilder::VclBuilder(vcl::Window* pParent, std::u16string_view sUIDir, const OUString& sUIFile,
                       OUString sID, css::uno::Reference<css::frame::XFrame> xFrame,
                       bool bLegacy, const NotebookBarAddonsItem* pNotebookBarAddonsItem)
    : WidgetBuilder(sUIDir, sUIFile, bLegacy)
    , m_pNotebookBarAddonsItem(pNotebookBarAddonsItem
                                   ? new NotebookBarAddonsItem(*pNotebookBarAddonsItem)
                                   : new NotebookBarAddonsItem{})
    , m_sID(std::move(sID))
    , m_pParent(pParent)
    , m_bToplevelParentFound(false)
    , m_pVclParserState(new VclParserState)
    , m_xFrame(std::move(xFrame))
{
    m_bToplevelHasDeferredInit = pParent &&
        ((pParent->IsSystemWindow() && static_cast<SystemWindow*>(pParent)->isDeferredInit()) ||
         (pParent->IsDockingWindow() && static_cast<DockingWindow*>(pParent)->isDeferredInit()));
    m_bToplevelHasDeferredProperties = m_bToplevelHasDeferredInit;

    processUIFile(pParent);

    //Set a11y relations and role when everything has been imported
    for (auto const& elemAtk : m_pVclParserState->m_aAtkInfo)
    {
        vcl::Window *pSource = elemAtk.first;
        const stringmap &rMap = elemAtk.second;

        for (auto const& [ rType, rParam ] : rMap)
        {
            if (rType == "role")
            {
                sal_Int16 role = BuilderUtils::getRoleFromName(rParam);
                if (role != css::accessibility::AccessibleRole::UNKNOWN)
                    pSource->SetAccessibleRole(role);
            }
            else
            {
                vcl::Window *pTarget = get(rParam);
                SAL_WARN_IF(!pTarget, "vcl""missing parameter of a11y relation: " << rParam);
                if (!pTarget)
                    continue;
                if (rType == "labelled-by")
                    pSource->SetAccessibleRelationLabeledBy(pTarget);
                else if (rType == "label-for")
                    pSource->SetAccessibleRelationLabelFor(pTarget);
                else
                {
                    SAL_WARN("vcl.builder""unhandled a11y relation :" << rType);
                }
            }
        }
    }

#ifndef NDEBUG
    o3tl::sorted_vector<OUString> models;
#endif
    //Set ComboBox models when everything has been imported
    for (auto const& elem : m_pVclParserState->m_aModelMaps)
    {
        assert(models.insert(elem.m_sValue).second && "a liststore or treestore is used in duplicate widgets");
        vcl::Window* pTarget = get(elem.m_sID);
        ListBox *pListBoxTarget = dynamic_cast<ListBox*>(pTarget);
        ComboBox *pComboBoxTarget = dynamic_cast<ComboBox*>(pTarget);
        SvTabListBox *pTreeBoxTarget = dynamic_cast<SvTabListBox*>(pTarget);
        // pStore may be empty
        const ListStore *pStore = get_model_by_name(elem.m_sValue);
        SAL_WARN_IF(!pListBoxTarget && !pComboBoxTarget && !pTreeBoxTarget && !dynamic_cast<IconView*>(pTarget), "vcl""missing elements of combobox");
        if (pListBoxTarget && pStore)
            mungeModel(*pListBoxTarget, *pStore, elem.m_nActiveId);
        else if (pComboBoxTarget && pStore)
            mungeModel(*pComboBoxTarget, *pStore, elem.m_nActiveId);
        else if (pTreeBoxTarget && pStore)
            mungeModel(*pTreeBoxTarget, *pStore, elem.m_nActiveId);
    }

    //Set TextView buffers when everything has been imported
    for (auto const& elem : m_pVclParserState->m_aTextBufferMaps)
    {
        VclMultiLineEdit *pTarget = get<VclMultiLineEdit>(elem.m_sID);
        const TextBuffer *pBuffer = get_buffer_by_name(elem.m_sValue);
        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 (auto const& elem : m_pVclParserState->m_aNumericFormatterAdjustmentMaps)
    {
        NumericFormatter *pTarget = dynamic_cast<NumericFormatter*>(get(elem.m_sID));
        const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue);
        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 (auto const& elem : m_pVclParserState->m_aFormattedFormatterAdjustmentMaps)
    {
        FormattedField *pTarget = dynamic_cast<FormattedField*>(get(elem.m_sID));
        const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue);
        SAL_WARN_IF(!pTarget, "vcl""missing FormattedField element of spinbutton/adjustment");
        SAL_WARN_IF(!pAdjustment, "vcl""missing Adjustment element of spinbutton/adjustment");
        if (pTarget && pAdjustment)
            mungeAdjustment(*pTarget, *pAdjustment);
    }

    //Set ScrollBar adjustments when everything has been imported
    for (auto const& elem : m_pVclParserState->m_aScrollAdjustmentMaps)
    {
        ScrollBar *pTarget = get<ScrollBar>(elem.m_sID);
        const Adjustment *pAdjustment = get_adjustment_by_name(elem.m_sValue);
        SAL_WARN_IF(!pTarget || !pAdjustment, "vcl""missing elements of scrollbar/adjustment");
        if (pTarget && pAdjustment)
            mungeAdjustment(*pTarget, *pAdjustment);
    }

    //Set Scale(Slider) adjustments
    for (auto const& elem : m_pVclParserState->m_aSliderAdjustmentMaps)
    {
        Slider* pTarget = dynamic_cast<Slider*>(get(elem.m_sID));
        const Adjustment* pAdjustment = get_adjustment_by_name(elem.m_sValue);
        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 (auto const& sizeGroup : getSizeGroups())
    {
        std::shared_ptr<VclSizeGroup> xGroup(std::make_shared<VclSizeGroup>());

        for (auto const& [ rKey, rValue ] : sizeGroup.m_aProperties)
            xGroup->set_property(rKey, rValue);

        for (auto const& elem : sizeGroup.m_aWidgets)
        {
            vcl::Window* pWindow = get(elem);
            pWindow->add_to_size_group(xGroup);
        }
    }

    //Set button images when everything has been imported
    std::set<OUString> aImagesToBeRemoved;
    for (auto const& elem : m_pVclParserState->m_aButtonImageWidgetMaps)
    {
        PushButton *pTargetButton = nullptr;
        RadioButton *pTargetRadio = nullptr;
        Button *pTarget = nullptr;

        if (!elem.m_bRadio)
        {
            pTargetButton = get<PushButton>(elem.m_sID);
            pTarget = pTargetButton;
        }
        else
        {
            pTargetRadio = get<RadioButton>(elem.m_sID);
            pTarget = pTargetRadio;
        }

        FixedImage *pImage = get<FixedImage>(elem.m_sValue);
        SAL_WARN_IF(!pTarget || !pImage,
            "vcl""missing elements of button/image/stock");
        if (!pTarget || !pImage)
            continue;
        aImagesToBeRemoved.insert(elem.m_sValue);

        if (!elem.m_bRadio)
        {
            const Image& rImage = pImage->GetImage();
            SymbolType eSymbol = mapStockToSymbol(rImage.GetStock());
            if (eSymbol != SymbolType::IMAGE && eSymbol != SymbolType::DONTKNOW)
            {
                pTargetButton->SetSymbol(eSymbol);
                //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
                pTargetButton->SetStyle(pTargetButton->GetStyle() | WB_SMALLSTYLE);
            }
            else
            {
                pTargetButton->SetModeImage(rImage);
                if (pImage->GetStyle() & WB_SMALLSTYLE)
                {
                    Size aSz(rImage.GetSizePixel());
                    aSz.AdjustWidth(6);
                    aSz.AdjustHeight(6);
                    if (pTargetButton->get_width_request() == -1)
                        pTargetButton->set_width_request(aSz.Width());
                    if (pTargetButton->get_height_request() == -1)
                        pTargetButton->set_height_request(aSz.Height());
                }
            }
        }
        else
            pTargetRadio->SetModeRadioImage(pImage->GetImage());

        auto aFind = m_pVclParserState->m_aImageSizeMap.find(elem.m_sValue);
        if (aFind != m_pVclParserState->m_aImageSizeMap.end())
        {
            switch (aFind->second)
            {
                case 1:
                    pTarget->SetSmallSymbol();
                    break;
                case 2:
                    assert(pImage->GetStyle() & WB_SMALLSTYLE);
                    pTarget->SetStyle(pTarget->GetStyle() | WB_SMALLSTYLE);
                    break;
                case 3:
                    pTarget->SetStyle(pTarget->GetStyle() | WB_SMALLSTYLE);
                    // large toolbar, make bigger than normal (4)
                    pTarget->set_width_request(pTarget->GetOptimalSize().Width() * 1.5);
                    pTarget->set_height_request(pTarget->GetOptimalSize().Height() * 1.5);
                    break;
                case 4:
                    break;
                default:
                    SAL_WARN("vcl.builder""unsupported image size " << aFind->second);
                    break;
            }
            m_pVclParserState->m_aImageSizeMap.erase(aFind);
        }
    }

    //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 (auto const& elem : aImagesToBeRemoved)
    {
        delete_by_name(elem);
    }

    //Set button menus when everything has been imported
    for (auto const& elem : m_pVclParserState->m_aButtonMenuMaps)
    {
        MenuButton *pTarget = get<MenuButton>(elem.m_sID);
        PopupMenu *pMenu = get_menu(elem.m_sValue);
        SAL_WARN_IF(!pTarget || !pMenu,
            "vcl""missing elements of button/menu");
        if (!pTarget || !pMenu)
            continue;
        pTarget->SetPopupMenu(pMenu, true);
    }

    //Remove ScrollWindow parent widgets whose children in vcl implement scrolling
    //internally.
    for (auto const& elem : m_pVclParserState->m_aRedundantParentWidgets)
    {
        delete_by_window(elem.first);
    }

    //fdo#67378 merge the label into the disclosure button
    for (auto const& elem : m_pVclParserState->m_aExpanderWidgets)
    {
        vcl::Window *pChild = elem->get_child();
        vcl::Window* pLabel = elem->GetWindow(GetWindowType::LastChild);
        if (pLabel && pLabel != pChild && pLabel->GetType() == WindowType::FIXEDTEXT)
        {
            FixedText *pLabelWidget = static_cast<FixedText*>(pLabel);
            elem->set_label(pLabelWidget->GetText());
            if (pLabelWidget->IsControlFont())
                elem->get_label_widget()->SetControlFont(pLabelWidget->GetControlFont());
            delete_by_window(pLabel);
        }
    }

    // create message dialog message area now
    for (auto const& elem : m_pVclParserState->m_aMessageDialogs)
        elem->create_message_area();

    //drop maps, etc. that we don't need again
    resetParserState();

    SAL_WARN_IF(!m_sID.isEmpty() && (!m_bToplevelParentFound && !get_by_name(m_sID)), "vcl.builder",
        "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 (auto const& child : m_aChildren)
        {
            if (isButtonType(child.m_pWindow->GetType()))
            {
                ++nButtons;
                if (child.m_pWindow->GetStyle() & WB_DEFBUTTON)
                {
                    bHasDefButton = true;
                    break;
                }
            }
        }
        SAL_WARN_IF(nButtons && !bHasDefButton, "vcl.builder""No default button defined in " << sUIFile);
    }
#endif

    const bool bHideHelp = comphelper::LibreOfficeKit::isActive() &&
        officecfg::Office::Common::Help::HelpRootURL::get().isEmpty();
    if (bHideHelp)
    {
        if (vcl::Window *pHelpButton = get(u"help"))
            pHelpButton->Hide();
    }
}

VclBuilder::~VclBuilder()
{
    disposeBuilder();
}

void VclBuilder::disposeBuilder()
{
    for (std::vector<WinAndId>::reverse_iterator aI = m_aChildren.rbegin(),
         aEnd = m_aChildren.rend(); aI != aEnd; ++aI)
    {
        aI->m_pWindow.disposeAndClear();
    }
    m_aChildren.clear();

    for (std::vector<MenuAndId>::reverse_iterator aI = m_aMenus.rbegin(),
         aEnd = m_aMenus.rend(); aI != aEnd; ++aI)
    {
        aI->m_pMenu.disposeAndClear();
    }
    m_aMenus.clear();
    m_pParent.reset();
}

namespace
{
    inline OUString extractStringEntry(BuilderBase::stringmap& rMap, const OUString&&nbsp;rKey,
                                       const OUString& rDefaultValue = OUString())
    {
        BuilderBase::stringmap::iterator aFind = rMap.find(rKey);
        if (aFind != rMap.end())
        {
            const OUString sValue = aFind->second;
            rMap.erase(aFind);
            return sValue;
        }
        return rDefaultValue;
    }

    inline bool extractBoolEntry(BuilderBase::stringmap& rMap, const OUString& rKey, bool bDefaultValue)
    {
        BuilderBase::stringmap::iterator aFind = rMap.find(rKey);
        if (aFind != rMap.end())
        {
            const bool bValue = toBool(aFind->second);
            rMap.erase(aFind);
            return bValue;
        }
        return bDefaultValue;
    }

    bool extractHasFrame(VclBuilder::stringmap& rMap)
    {
        return extractBoolEntry(rMap, u"has-frame"_ustr, true);
    }

    bool extractDrawValue(VclBuilder::stringmap& rMap)
    {
        return extractBoolEntry(rMap, u"draw-value"_ustr, true);
    }

    OUString extractWidgetName(VclBuilder::stringmap& rMap)
    {
        return extractStringEntry(rMap, u"name"_ustr);
    }

    OUString extractValuePos(VclBuilder::stringmap& rMap)
    {
        return extractStringEntry(rMap,u"value-pos"_ustr, u"top"_ustr);
    }

    OUString extractTypeHint(VclBuilder::stringmap &rMap)
    {
        return extractStringEntry(rMap, u"type-hint"_ustr, u"normal"_ustr);
    }

    bool extractModal(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"modal"_ustr, false);
    }

    bool extractDecorated(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"decorated"_ustr, true);
    }

    bool extractCloseable(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"deletable"_ustr, true);
    }

    bool extractVerticalTabPos(VclBuilder::stringmap &rMap)
    {
        bool bVertical = false;
        VclBuilder::stringmap::iterator aFind = rMap.find(u"tab-pos"_ustr);
        if (aFind != rMap.end())
        {
            bVertical = aFind->second.equalsIgnoreAsciiCase("left") ||
                        aFind->second.equalsIgnoreAsciiCase("right");
            rMap.erase(aFind);
        }
        return bVertical;
    }

    bool extractVerticalTabsWithIcons(VclBuilder::stringmap &rMap)
    {
        bool bWithIcons = false;
        VclBuilder::stringmap::iterator aFind = rMap.find(u"group-name"_ustr);
        if (aFind != rMap.end())
        {
            bWithIcons = aFind->second.equalsIgnoreAsciiCase("icons");
            rMap.erase(aFind);
        }
        return bWithIcons;
    }

    bool extractInconsistent(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"inconsistent"_ustr, false);
    }

    WinBits extractRelief(VclBuilder::stringmap &rMap)
    {
        WinBits nBits = WB_3DLOOK;
        VclBuilder::stringmap::iterator aFind = rMap.find(u"relief"_ustr);
        if (aFind != rMap.end())
        {
            assert(aFind->second != "half" && "relief of 'half' unsupported");
            if (aFind->second == "none")
                nBits = WB_FLATBUTTON;
            rMap.erase(aFind);
        }
        return nBits;
    }

    Size extractSizeRequest(VclBuilder::stringmap &rMap)
    {
        OUString sWidthRequest(u"0"_ustr);
        OUString sHeightRequest(u"0"_ustr);
        VclBuilder::stringmap::iterator aFind = rMap.find(u"width-request"_ustr);
        if (aFind != rMap.end())
        {
            sWidthRequest = aFind->second;
            rMap.erase(aFind);
        }
        aFind = rMap.find(u"height-request"_ustr);
        if (aFind != rMap.end())
        {
            sHeightRequest = aFind->second;
            rMap.erase(aFind);
        }
        return Size(sWidthRequest.toInt32(), sHeightRequest.toInt32());
    }

    float extractAlignment(VclBuilder::stringmap &rMap)
    {
        float f = 0.0;
        VclBuilder::stringmap::iterator aFind = rMap.find(u"alignment"_ustr);
        if (aFind != rMap.end())
        {
            f = aFind->second.toFloat();
            rMap.erase(aFind);
        }
        return f;
    }

    bool extractSortIndicator(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"sort-indicator"_ustr, false);
    }

    bool extractClickable(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"clickable"_ustr, false);
    }

    void setupFromActionName(Button *pButton, VclBuilder::stringmap &rMap, const css::uno::Reference<css::frame::XFrame>& rFrame)
    {
        if (!rFrame.is())
            return;

        OUString aCommand(BuilderBase::extractActionName(rMap));
        if (aCommand.isEmpty())
            return;

        OUString aModuleName(vcl::CommandInfoProvider::GetModuleIdentifier(rFrame));
        auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(aCommand, aModuleName);
        OUString aLabel(vcl::CommandInfoProvider::GetLabelForCommand(aProperties));
        if (!aLabel.isEmpty())
            pButton->SetText(aLabel);

        OUString aTooltip(vcl::CommandInfoProvider::GetTooltipForCommand(aCommand, aProperties, rFrame));
        if (!aTooltip.isEmpty())
            pButton->SetQuickHelpText(aTooltip);

        Image aImage(vcl::CommandInfoProvider::GetImageForCommand(aCommand, rFrame));
        pButton->SetModeImage(aImage);

        pButton->SetCommandHandler(aCommand, rFrame);
    }

    VclPtr<Button> extractStockAndBuildPushButton(vcl::Window *pParent, VclBuilder::stringmap &rMap, bool bToggle)
    {
        WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER;
        if (bToggle)
            nBits |= WB_TOGGLE;

        nBits |= extractRelief(rMap);

        VclPtr<Button> xWindow = VclPtr<PushButton>::Create(pParent, nBits);
        return xWindow;
    }

    VclPtr<MenuButton> extractStockAndBuildMenuButton(vcl::Window *pParent, VclBuilder::stringmap &rMap)
    {
        WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK;

        nBits |= extractRelief(rMap);

        VclPtr<MenuButton> xWindow = VclPtr<MenuButton>::Create(pParent, nBits);
        return xWindow;
    }

    VclPtr<MenuButton> extractStockAndBuildMenuToggleButton(vcl::Window *pParent, VclBuilder::stringmap &rMap)
    {
        WinBits nBits = WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_3DLOOK;

        nBits |= extractRelief(rMap);

        VclPtr<MenuButton> xWindow = VclPtr<MenuToggleButton>::Create(pParent, nBits);
        return xWindow;
    }

    WinBits extractDeferredBits(VclBuilder::stringmap &rMap)
    {
        WinBits nBits = WB_3DLOOK|WB_HIDE;
        if (BuilderBase::extractResizable(rMap))
            nBits |= WB_SIZEABLE;
        if (extractCloseable(rMap))
            nBits |= WB_CLOSEABLE;
        if (!extractDecorated(rMap))
            nBits |= WB_OWNERDRAWDECORATION;
        OUString sType(extractTypeHint(rMap));
        if (sType == "utility")
            nBits |= WB_SYSTEMWINDOW | WB_DIALOGCONTROL | WB_MOVEABLE;
        else if (sType == "popup-menu")
            nBits |= WB_SYSTEMWINDOW | WB_DIALOGCONTROL | WB_POPUP;
        else if (sType == "dock")
            nBits |= WB_DOCKABLE | WB_MOVEABLE;
        else
            nBits |= WB_MOVEABLE;
        return nBits;
    }
}

void BuilderBase::extractRadioButtonGroup(const OUString &id, stringmap &rMap)
{
    const OUString sGroupId = extractGroup(rMap);
    if (sGroupId.isEmpty())
        return;

    m_pParserState->m_aRadioButtonGroupMaps.emplace_back(id, sGroupId);
}

void VclBuilder::connectNumericFormatterAdjustment(const OUString &id, const OUString &rAdjustment)
{
    if (!rAdjustment.isEmpty())
        m_pVclParserState->m_aNumericFormatterAdjustmentMaps.emplace_back(id, rAdjustment);
}

void VclBuilder::connectFormattedFormatterAdjustment(const OUString &id, const OUString &rAdjustment)
{
    if (!rAdjustment.isEmpty())
        m_pVclParserState->m_aFormattedFormatterAdjustmentMaps.emplace_back(id, rAdjustment);
}

bool VclBuilder::extractAdjustmentToMap(const OUString& id, VclBuilder::stringmap& rMap, std::vector<WidgetAdjustmentMap>& rAdjustmentMap)
{
    VclBuilder::stringmap::iterator aFind = rMap.find(u"adjustment"_ustr);
    if (aFind != rMap.end())
    {
        rAdjustmentMap.emplace_back(id, aFind->second);
        rMap.erase(aFind);
        return true;
    }
    return false;
}

namespace
{
    bool extractSelectable(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"selectable"_ustr, false);
    }

    OUString extractAdjustment(VclBuilder::stringmap &rMap)
    {
        OUString sAdjustment;
        VclBuilder::stringmap::iterator aFind = rMap.find(u"adjustment"_ustr);
        if (aFind != rMap.end())
        {
            sAdjustment= aFind->second;
            rMap.erase(aFind);
            return sAdjustment;
        }
        return sAdjustment;
    }

    bool extractDrawIndicator(VclBuilder::stringmap &rMap)
    {
        return extractBoolEntry(rMap, u"draw-indicator"_ustr, false);
    }
}

void VclBuilder::extractModel(const OUString &id, stringmap &rMap)
{
    VclBuilder::stringmap::iterator aFind = rMap.find(u"model"_ustr);
    if (aFind != rMap.end())
    {
        m_pVclParserState->m_aModelMaps.emplace_back(id, aFind->second,
            extractActive(rMap));
        rMap.erase(aFind);
    }
}

void VclBuilder::extractBuffer(const OUString &id, stringmap &rMap)
{
    VclBuilder::stringmap::iterator aFind = rMap.find(u"buffer"_ustr);
    if (aFind != rMap.end())
    {
        m_pVclParserState->m_aTextBufferMaps.emplace_back(id, aFind->second);
        rMap.erase(aFind);
    }
}

int VclBuilder::getImageSize(const stringmap &rMap)
{
    int nSize = 4;
    auto aFind = rMap.find(u"icon-size"_ustr);
    if (aFind != rMap.end())
        nSize = aFind->second.toInt32();
    return nSize;
}

void VclBuilder::extractButtonImage(const OUString &id, stringmap &rMap, bool bRadio)
{
    VclBuilder::stringmap::iterator aFind = rMap.find(u"image"_ustr);
    if (aFind != rMap.end())
    {
        m_pVclParserState->m_aButtonImageWidgetMaps.emplace_back(id, aFind->second, bRadio);
        rMap.erase(aFind);
    }
}

void BuilderBase::extractMnemonicWidget(const OUString &rLabelID, stringmap &rMap)
{
    VclBuilder::stringmap::iterator aFind = rMap.find(u"mnemonic-widget"_ustr);
    if (aFind != rMap.end())
    {
        OUString sID = aFind->second;
        sal_Int32 nDelim = sID.indexOf(':');
        if (nDelim != -1)
            sID = sID.copy(0, nDelim);
        m_pParserState->m_aMnemonicWidgetMaps.emplace_back(rLabelID, sID);
        rMap.erase(aFind);
    }
}

vcl::Window* VclBuilder::prepareWidgetOwnScrolling(vcl::Window *pParent, WinBits &rWinStyle)
{
    //For Widgets that manage their own scrolling, if one appears as a child of
    //a scrolling window shoehorn that scrolling settings to this widget and
    //return the real parent to use
    if (pParent && pParent->GetType() == WindowType::SCROLLWINDOW)
    {
        WinBits nScrollBits = pParent->GetStyle();
        nScrollBits &= (WB_AUTOHSCROLL|WB_HSCROLL|WB_AUTOVSCROLL|WB_VSCROLL);
        rWinStyle |= nScrollBits;
        if (static_cast<VclScrolledWindow*>(pParent)->HasVisibleBorder())
            rWinStyle |= WB_BORDER;
        pParent = pParent->GetParent();
    }

    return pParent;
}

void VclBuilder::cleanupWidgetOwnScrolling(vcl::Window *pScrollParent, vcl::Window *pWindow, stringmap &rMap)
{
    //remove the redundant scrolling parent
    sal_Int32 nWidthReq = pScrollParent->get_width_request();
    rMap[u"width-request"_ustr] = OUString::number(nWidthReq);
    sal_Int32 nHeightReq = pScrollParent->get_height_request();
    rMap[u"height-request"_ustr] = OUString::number(nHeightReq);

    m_pVclParserState->m_aRedundantParentWidgets[pScrollParent] = pWindow;
}

#ifndef DISABLE_DYNLOADING

extern "C" { static void thisModule() {} }

namespace {

// Don't unload the module on destruction
class NoAutoUnloadModule : public osl::Module
{
public:
    ~NoAutoUnloadModule() { release(); }
};

}

typedef std::map<OUString, std::shared_ptr<NoAutoUnloadModule>> ModuleMap;
static ModuleMap g_aModuleMap;

#if ENABLE_MERGELIBS
static std::shared_ptr<NoAutoUnloadModule> g_pMergedLib = std::make_shared<NoAutoUnloadModule>();
#endif

#ifndef SAL_DLLPREFIX
#  define SAL_DLLPREFIX ""
#endif

#endif

namespace vcl {

void VclBuilderPreload()
{
#ifndef DISABLE_DYNLOADING

#if ENABLE_MERGELIBS
    g_pMergedLib->loadRelative(&thisModule, SVLIBRARY("merged"));
#else
// find -name '*ui*' | xargs grep 'class=".*lo-' |
//     sed 's/.*class="//' | sed 's/-.*$//' | sort | uniq
    static const char *aWidgetLibs[] = {
        "sfxlo",  "svtlo"
    };
    for (const auto & lib : aWidgetLibs)
    {
        std::unique_ptr<NoAutoUnloadModule> pModule(new NoAutoUnloadModule);
        OUString sModule = SAL_DLLPREFIX + OUString::createFromAscii(lib) + SAL_DLLEXTENSION;
        if (pModule->loadRelative(&thisModule, sModule))
            g_aModuleMap.insert(std::make_pair(sModule, std::move(pModule)));
    }
#endif // ENABLE_MERGELIBS
#endif // DISABLE_DYNLOADING
}

}

#if defined DISABLE_DYNLOADING && !HAVE_FEATURE_DESKTOP

// This ifdef branch is mainly for building for the Collabora Online
// -based mobile apps for Android and iOS.

extern "C" VclBuilder::customMakeWidget lo_get_custom_widget_func(const char* name);

#elif defined EMSCRIPTEN && !ENABLE_QT5

// This branch is mainly for building for WASM, and especially for
// Collabora Online in the browser, where code from core and Collabora
// Online is compiled to WASM and linked into a single WASM binary.
// (Not for Allotropia's Qt-based LibreOffice in the browser.)

// When building core for WASM it doesn't use the same
// solenv/bin/native-code.py thing as the mobile apps, even if in both
// cases everything is linked statically. So there is no generated
// native-code.h, and we can't use lo_get_custom_widget_func() from
// that. So cheat and duplicate the code from an existing generated
// native-code.h. It's just a handful of lines anyway.

extern "C" void makeNotebookbarTabControl(VclPtr<vcl::Window> &rRet, const VclPtr<vcl::Window> &pParent, VclBuilder::stringmap &rVec);
extern "C" void makeNotebookbarToolBox(VclPtr<vcl::Window> &rRet, const VclPtr<vcl::Window> &pParent,&nbsp;VclBuilder::stringmap &rVec);

static struct { const char *name; VclBuilder::customMakeWidget func; } custom_widgets[] = {
    { "makeNotebookbarTabControl", makeNotebookbarTabControl },
    { "makeNotebookbarToolBox", makeNotebookbarToolBox },
};

static VclBuilder::customMakeWidget lo_get_custom_widget_func(const char* name)
{
    for (size_t i = 0; i < sizeof(custom_widgets) / sizeof(custom_widgets[0]); i++)
        if (strcmp(name, custom_widgets[i].name) == 0)
            return custom_widgets[i].func;
    return nullptr;
}

#endif

namespace
{
// Takes a string like "sfxlo-NotebookbarToolBox"
VclBuilder::customMakeWidget GetCustomMakeWidget(const OUString& rName)
{
    const OUString name = rName == "sfxlo-SidebarToolBox" ? u"sfxlo-NotebookbarToolBox"_ustr : rName;
    VclBuilder::customMakeWidget pFunction = nullptr;
    if (sal_Int32 nDelim = name.indexOf('-'); nDelim != -1)
    {
        const OUString sFunction(OUString::Concat("make") + name.subView(nDelim + 1));

#ifndef DISABLE_DYNLOADING
        const OUString sModule = OUString::Concat(SAL_DLLPREFIX)
                                 + name.subView(0, nDelim)
                                 + SAL_DLLEXTENSION;
        ModuleMap::iterator aI = g_aModuleMap.find(sModule);
        if (aI == g_aModuleMap.end())
        {
            std::shared_ptr<NoAutoUnloadModule> pModule;
#if ENABLE_MERGELIBS
            if (!g_pMergedLib->is())
                g_pMergedLib->loadRelative(&thisModule, SVLIBRARY("merged"));
            if ((pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(
                     g_pMergedLib->getFunctionSymbol(sFunction))))
                pModule = g_pMergedLib;
#endif
            if (!pFunction)
            {
                pModule = std::make_shared<NoAutoUnloadModule>();
                bool ok = pModule->loadRelative(&thisModule, sModule);
                if (!ok)
                {
#ifdef LINUX
                    // in the case of preloading, we don't have eg. the
                    // libcuilo.so, but still need to dlsym the symbols -
                    // which are already in-process
                    if (comphelper::LibreOfficeKit::isActive())
                    {
                        pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(dlsym(RTLD_DEFAULT, OUStringToOString(sFunction, RTL_TEXTENCODING_UTF8).getStr()));
                        ok = !!pFunction;
                        assert(ok && "couldn't even directly dlsym the sFunction (available via preload)");
                    }
#endif
                    assert(ok && "bad module name in .ui");
                }
                else
                {
                    pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(
                            pModule->getFunctionSymbol(sFunction));
                }
            }
            g_aModuleMap.insert(std::make_pair(sModule, pModule));
        }
        else
            pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(
                aI->second->getFunctionSymbol(sFunction));
#elif !HAVE_FEATURE_DESKTOP || (defined EMSCRIPTEN && !ENABLE_QT5)
        // This ifdef branch is mainly for building for either the
        // Android or iOS apps, or the Collabora Online as WASM thing.
        pFunction = lo_get_custom_widget_func(sFunction.toUtf8().getStr());
        SAL_WARN_IF(!pFunction, "vcl.builder""Could not find " << sFunction);
        assert(pFunction);
#else
        pFunction = reinterpret_cast<VclBuilder::customMakeWidget>(
            osl_getFunctionSymbol((oslModule)RTLD_DEFAULT, sFunction.pData));
#endif
    }
    return pFunction;
}
}

VclPtr<vcl::Window> VclBuilder::makeObject(vcl::Window *pParent, const OUString &name, const OUString &id,
    stringmap &rMap)
{
    bool bIsPlaceHolder = name.isEmpty();
    bool bVertical = false;

    if (pParent && (pParent->GetType() == WindowType::TABCONTROL ||
                    pParent->GetType() == WindowType::VERTICALTABCONTROL))
    {
        bool bTopLevel(name == "GtkDialog" || name == "GtkMessageDialog" ||
                       name == "GtkWindow" || name == "GtkPopover" || name == "GtkAssistant");
        if (!bTopLevel)
        {
            if (pParent->GetType() == WindowType::TABCONTROL)
            {
                //We have to add a page
                //make default pageid == position
                TabControl *pTabControl = static_cast<TabControl*>(pParent);
                sal_uInt16 nNewPageCount = pTabControl->GetPageCount()+1;
                sal_uInt16 nNewPageId = nNewPageCount;
                pTabControl->InsertPage(nNewPageId, OUString());
                pTabControl->SetCurPageId(nNewPageId);
                SAL_WARN_IF(bIsPlaceHolder, "vcl.builder""we should have no placeholders for tabpages");
                if (!bIsPlaceHolder)
                {
                    VclPtrInstance<TabPage> pPage(pTabControl);
                    pPage->Show();

                    //Make up a name for it
                    OUString sTabPageId = get_by_window(pParent) +
                        "-page" +
                        OUString::number(nNewPageCount);
                    m_aChildren.emplace_back(sTabPageId, pPage, false);
                    pPage->SetHelpId(getHelpRoot() + sTabPageId);

                    pParent = pPage;

                    pTabControl->SetTabPage(nNewPageId, pPage);
                }
            }
            else
            {
                VerticalTabControl *pTabControl = static_cast<VerticalTabControl*>(pParent);
                SAL_WARN_IF(bIsPlaceHolder, "vcl.builder""we should have no placeholders for tabpages");
                if (!bIsPlaceHolder)
                    pParent = pTabControl->GetPageParent();
            }
        }
    }

    if (bIsPlaceHolder || name == "GtkTreeSelection")
        return nullptr;

    ToolBox *pToolBox = (pParent && pParent->GetType() == WindowType::TOOLBOX) ? static_cast<ToolBox*>(pParent) : nullptr;

    extractButtonImage(id, rMap, name == "GtkRadioButton");

    VclPtr<vcl::Window> xWindow;
    if (name == "GtkDialog" || name == "GtkAssistant")
    {
        // WB_ALLOWMENUBAR because we don't know in advance if we will encounter
        // a menubar, and menubars need a BorderWindow in the toplevel, and
        // such border windows need to be in created during the dialog ctor
        WinBits nBits = WB_MOVEABLE|WB_3DLOOK|WB_ALLOWMENUBAR;
        if (extractResizable(rMap))
            nBits |= WB_SIZEABLE;
        if (extractCloseable(rMap))
            nBits |= WB_CLOSEABLE;
        Dialog::InitFlag eInit = !pParent ? Dialog::InitFlag::NoParent : Dialog::InitFlag::Default;
        if (name == "GtkAssistant")
            xWindow = VclPtr<vcl::RoadmapWizard>::Create(pParent, nBits, eInit);
        else
            xWindow = VclPtr<Dialog>::Create(pParent, nBits, eInit);
#if HAVE_FEATURE_DESKTOP
        if (!extractModal(rMap))
            xWindow->SetType(WindowType::MODELESSDIALOG);
#endif
    }
    else if (name == "GtkMessageDialog")
    {
        WinBits nBits = WB_MOVEABLE|WB_3DLOOK|WB_CLOSEABLE;
        if (extractResizable(rMap))
            nBits |= WB_SIZEABLE;
        VclPtr<MessageDialog> xDialog(VclPtr<MessageDialog>::Create(pParent, nBits));
        m_pVclParserState->m_aMessageDialogs.push_back(xDialog);
        xWindow = xDialog;
#if defined _WIN32
        xWindow->set_border_width(3);
#else
        xWindow->set_border_width(12);
#endif
    }
    else if (name == "GtkBox" || name == "GtkStatusbar")
    {
        bVertical = hasOrientationVertical(rMap);
        if (bVertical)
            xWindow = VclPtr<VclVBox>::Create(pParent);
        else
            xWindow = VclPtr<VclHBox>::Create(pParent);

        if (name == "GtkStatusbar")
            xWindow->SetAccessibleRole(css::accessibility::AccessibleRole::STATUS_BAR);
    }
    else if (name == "GtkPaned")
    {
        bVertical = hasOrientationVertical(rMap);
        if (bVertical)
            xWindow = VclPtr<VclVPaned>::Create(pParent);
        else
            xWindow = VclPtr<VclHPaned>::Create(pParent);
    }
    else if (name == "GtkHBox")
        xWindow = VclPtr<VclHBox>::Create(pParent);
    else if (name == "GtkVBox")
        xWindow = VclPtr<VclVBox>::Create(pParent);
    else if (name == "GtkButtonBox")
    {
        bVertical = hasOrientationVertical(rMap);
        if (bVertical)
            xWindow = VclPtr<VclVButtonBox>::Create(pParent);
        else
            xWindow = VclPtr<VclHButtonBox>::Create(pParent);
    }
    else if (name == "GtkHButtonBox")
        xWindow = VclPtr<VclHButtonBox>::Create(pParent);
    else if (name == "GtkVButtonBox")
        xWindow = VclPtr<VclVButtonBox>::Create(pParent);
    else if (name == "GtkGrid")
        xWindow = VclPtr<VclGrid>::Create(pParent);
    else if (name == "GtkFrame")
        xWindow = VclPtr<VclFrame>::Create(pParent);
    else if (name == "GtkExpander")
    {
        VclPtrInstance<VclExpander> pExpander(pParent);
        m_pVclParserState->m_aExpanderWidgets.push_back(pExpander);
        xWindow = pExpander;
    }
    else if (name == "GtkButton" || (!isLegacy() && name == "GtkToggleButton"))
    {
        VclPtr<Button> xButton;
        OUString sMenu = BuilderUtils::extractCustomProperty(rMap);
        if (sMenu.isEmpty())
            xButton = extractStockAndBuildPushButton(pParent, rMap, name == "GtkToggleButton");
        else
        {
            assert(isLegacy() && "use GtkMenuButton");
            xButton = extractStockAndBuildMenuButton(pParent, rMap);
            m_pVclParserState->m_aButtonMenuMaps.emplace_back(id, sMenu);
        }
        xButton->SetImageAlign(ImageAlign::Left); //default to left
        setupFromActionName(xButton, rMap, m_xFrame);
        xWindow = xButton;
    }
    else if (name == "GtkMenuButton")
    {
        VclPtr<MenuButton> xButton;

        OUString sMenu = extractPopupMenu(rMap);
        if (!sMenu.isEmpty())
            m_pVclParserState->m_aButtonMenuMaps.emplace_back(id, sMenu);

        OUString sType = extractWidgetName(rMap);
        if (sType.isEmpty())
        {
            xButton = extractStockAndBuildMenuButton(pParent, rMap);
            xButton->SetAccessibleRole(css::accessibility::AccessibleRole::BUTTON_MENU);
        }
        else
        {
            xButton = extractStockAndBuildMenuToggleButton(pParent, rMap);
        }

        xButton->SetImageAlign(ImageAlign::Left); //default to left

        if (!extractDrawIndicator(rMap))
            xButton->SetDropDown(PushButtonDropdownStyle::NONE);

        setupFromActionName(xButton, rMap, m_xFrame);
        xWindow = xButton;
    }
    else if (name == "GtkToggleButton" && isLegacy())
    {
        VclPtr<Button> xButton;
        OUString sMenu = BuilderUtils::extractCustomProperty(rMap);
        assert(sMenu.getLength() && "not implemented yet");
        xButton = extractStockAndBuildMenuToggleButton(pParent, rMap);
        m_pVclParserState->m_aButtonMenuMaps.emplace_back(id, sMenu);
        xButton->SetImageAlign(ImageAlign::Left); //default to left
        setupFromActionName(xButton, rMap, m_xFrame);
        xWindow = xButton;
    }
    else if (name == "GtkRadioButton")
    {
        extractRadioButtonGroup(id, rMap);
        WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK;
        VclPtr<RadioButton> xButton = VclPtr<RadioButton>::Create(pParent, true, nBits);
        xButton->SetImageAlign(ImageAlign::Left); //default to left
        xWindow = xButton;
    }
    else if (name == "GtkCheckButton")
    {
        WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK;
        bool bIsTriState = extractInconsistent(rMap);
        VclPtr<CheckBox> xCheckBox = VclPtr<CheckBox>::Create(pParent, nBits);
        if (bIsTriState)
        {
            xCheckBox->EnableTriState(true);
            xCheckBox->SetState(TRISTATE_INDET);
        }
        xCheckBox->SetImageAlign(ImageAlign::Left); //default to left

        xWindow = xCheckBox;
    }
    else if (name == "GtkSpinButton")
    {
        OUString sAdjustment = extractAdjustment(rMap);

        WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_3DLOOK|WB_SPIN|WB_REPEAT;
        if (extractHasFrame(rMap))
            nBits |= WB_BORDER;

        connectFormattedFormatterAdjustment(id, sAdjustment);
        VclPtrInstance<FormattedField> xField(pParent, nBits);
        xField->GetFormatter().SetMinValue(0);
        xWindow = xField;
    }
    else if (name == "GtkLinkButton")
        xWindow = VclPtr<FixedHyperlink>::Create(pParent, WB_CENTER|WB_VCENTER|WB_3DLOOK|WB_NOLABEL);
    else if (name == "GtkComboBox" || name == "GtkComboBoxText")
    {
        extractModel(id, rMap);

        WinBits nBits = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK;

        bool bDropdown = BuilderUtils::extractDropdown(rMap);

        if (bDropdown)
            nBits |= WB_DROPDOWN;

        if (extractEntry(rMap))
        {
            VclPtrInstance<ComboBox> xComboBox(pParent, nBits);
            xComboBox->EnableAutoSize(true);
            xWindow = xComboBox;
        }
        else
        {
            VclPtrInstance<ListBox> xListBox(pParent, nBits|WB_SIMPLEMODE);
            xListBox->EnableAutoSize(true);
            xWindow = xListBox;
        }
    }
    else if (name == "VclOptionalBox" || name == "sfxlo-OptionalBox")
    {
        // tdf#135495 fallback sfxlo-OptionalBox to VclOptionalBox as a stopgap
        xWindow = VclPtr<OptionalBox>::Create(pParent);
    }
    else if (name == "svtlo-ManagedMenuButton")
    {
        // like tdf#135495 keep the name svtlo-ManagedMenuButton even though it's a misnomer
        // and is not dlsymed from the svt library
        xWindow = VclPtr<ManagedMenuButton>::Create(pParent, WB_CLIPCHILDREN|WB_CENTER|WB_VCENTER|WB_FLATBUTTON);
        OUString sMenu = BuilderUtils::extractCustomProperty(rMap);
        if (!sMenu.isEmpty())
            m_pVclParserState->m_aButtonMenuMaps.emplace_back(id, sMenu);
        setupFromActionName(static_cast<Button*>(xWindow.get()), rMap, m_xFrame);
    }
    else if (name == "sfxlo-PriorityMergedHBox")
    {
        // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
        xWindow = VclPtr<PriorityMergedHBox>::Create(pParent);
    }
    else if (name == "sfxlo-PriorityHBox")
    {
        // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
        xWindow = VclPtr<PriorityHBox>::Create(pParent);
    }
    else if (name == "sfxlo-DropdownBox")
    {
        // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
        xWindow = VclPtr<DropdownBox>::Create(pParent);
    }
    else if (name == "sfxlo-ContextVBox")
    {
        // like tdf#135495 above, keep the sfxlo-PriorityMergedHBox even though its not in sfx anymore
        xWindow = VclPtr<ContextVBox>::Create(pParent);
    }
    else if (name == "GtkIconView")
    {
        assert(rMap.contains(u"model"_ustr) && "GtkIconView must have a model");

        //window we want to apply the packing props for this GtkIconView to
        VclPtr<vcl::Window> xWindowForPackingProps;
        extractModel(id, rMap);
        WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK;
        //IconView manages its own scrolling,
        vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle);

        VclPtr<IconView> xBox = VclPtr<IconView>::Create(pRealParent, nWinStyle);
        xWindowForPackingProps = xBox;

        xWindow = xBox;
        xBox->SetNoAutoCurEntry(true);
        xBox->SetQuickSearch(true);

        if (pRealParent != pParent)
            cleanupWidgetOwnScrolling(pParent, xWindowForPackingProps, rMap);
    }
    else if (name == "GtkTreeView")
    {
        if (!isLegacy())
        {
            assert(rMap.contains(u"model"_ustr) && "GtkTreeView must have a model");
        }

        //window we want to apply the packing props for this GtkTreeView to
        VclPtr<vcl::Window> xWindowForPackingProps;
        //To-Do
        //a) make SvHeaderTabListBox/SvTabListBox the default target for GtkTreeView
        //b) remove the non-drop down mode of ListBox and convert
        //   everything over to SvHeaderTabListBox/SvTabListBox
        extractModel(id, rMap);
        WinBits nWinStyle = WB_CLIPCHILDREN|WB_LEFT|WB_VCENTER|WB_3DLOOK;
        if (isLegacy())
        {
            OUString sBorder = BuilderUtils::extractCustomProperty(rMap);
            if (!sBorder.isEmpty())
                nWinStyle |= WB_BORDER;
        }
        else
        {
            nWinStyle |= WB_HASBUTTONS | WB_HASBUTTONSATROOT;
        }
        //ListBox/SvHeaderTabListBox manages its own scrolling,
        vcl::Window *pRealParent = prepareWidgetOwnScrolling(pParent, nWinStyle);
        if (isLegacy())
        {
            xWindow = VclPtr<ListBox>::Create(pRealParent, nWinStyle | WB_SIMPLEMODE);
            xWindowForPackingProps = xWindow;
        }
        else
        {
            VclPtr<SvTabListBox> xBox;
            bool bHeadersVisible = extractHeadersVisible(rMap);
            if (bHeadersVisible)
            {
                VclPtr<VclVBox> xContainer = VclPtr<VclVBox>::Create(pRealParent);
                OUString containerid(id + "-container");
                xContainer->SetHelpId(getHelpRoot() + containerid);
                m_aChildren.emplace_back(containerid, xContainer, true);

                VclPtrInstance<HeaderBar> xHeader(xContainer, WB_BUTTONSTYLE | WB_BORDER | WB_TABSTOP | WB_3DLOOK);
                xHeader->set_width_request(0); // let the headerbar width not affect the size request
                OUString headerid(id + "-header");
                xHeader->SetHelpId(getHelpRoot() + headerid);
                m_aChildren.emplace_back(headerid, xHeader, true);

                VclPtr<SvHeaderTabListBox> xHeaderBox = VclPtr<SvHeaderTabListBox>::Create(xContainer, nWinStyle, xHeader);
                xContainer->set_expand(true);
                xHeader->Show();
                xContainer->Show();
                xBox = xHeaderBox;
                xWindowForPackingProps = xContainer;
            }
            else
            {
                xBox = VclPtr<LclTabListBox>::Create(pRealParent, nWinStyle);
                xWindowForPackingProps = xBox;
            }
            xWindow = xBox;
            xBox->SetNoAutoCurEntry(true);
            xBox->SetQuickSearch(true);
            xBox->SetSpaceBetweenEntries(3);
            xBox->SetEntryHeight(16);
            xBox->SetHighlightRange(); // select over the whole width
        }
        if (pRealParent != pParent)
            cleanupWidgetOwnScrolling(pParent, xWindowForPackingProps, rMap);
    }
    else if (name == "GtkTreeViewColumn")
    {
        if (!isLegacy())
        {
            SvHeaderTabListBox* pTreeView = dynamic_cast<SvHeaderTabListBox*>(pParent);
            if (HeaderBar* pHeaderBar = pTreeView ? pTreeView->GetHeaderBar() : nullptr)
            {
                HeaderBarItemBits nBits = HeaderBarItemBits::LEFTIMAGE;
                if (extractClickable(rMap))
                    nBits |= HeaderBarItemBits::CLICKABLE;
                if (extractSortIndicator(rMap))
                    nBits |= HeaderBarItemBits::DOWNARROW;
                float fAlign = extractAlignment(rMap);
                if (fAlign == 0.0)
                    nBits |= HeaderBarItemBits::LEFT;
--> --------------------

--> maximum size reached

--> --------------------

Messung V0.5
C=93 H=84 G=88

¤ Dauer der Verarbeitung: 0.29 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.