Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  StyleList.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/.
 *
 * This file incorporates work covered by the following license notice:
 *
 *   Licensed to the Apache Software Foundation (ASF) under one or more
 *   contributor license agreements. See the NOTICE file distributed
 *   with this work for additional information regarding copyright
 *   ownership. The ASF licenses this file to you under the Apache
 *   License, Version 2.0 (the "License"); you may not use this file
 *   except in compliance with the License. You may obtain a copy of
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
 */


#include <memory>
#include <unordered_map>

#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/container/XNameAccess.hpp>
#include <utility>
#include <vcl/commandevent.hxx>
#include <vcl/commandinfoprovider.hxx>
#include <vcl/event.hxx>
#include <vcl/settings.hxx>
#include <vcl/svapp.hxx>
#include <vcl/weldutils.hxx>
#include <vcl/window.hxx>
#include <svl/intitem.hxx>
#include <svl/style.hxx>
#include <svl/itemset.hxx>
#include <comphelper/lok.hxx>
#include <comphelper/processfactory.hxx>
#include <officecfg/Office/Common.hxx>

#include <osl/diagnose.h>
#include <sfx2/dispatch.hxx>
#include <sfx2/bindings.hxx>
#include <templdgi.hxx>
#include <tplcitem.hxx>
#include <sfx2/styfitem.hxx>
#include <sfx2/objsh.hxx>
#include <sfx2/viewsh.hxx>
#include <sfx2/newstyle.hxx>
#include <sfx2/tplpitem.hxx>
#include <sfx2/sfxresid.hxx>

#include <sfx2/sfxsids.hrc>
#include <sfx2/strings.hrc>
#include <sfx2/docfac.hxx>
#include <sfx2/module.hxx>
#include <helpids.h>
#include <sfx2/viewfrm.hxx>

#include <comphelper/string.hxx>

#include <sfx2/StyleManager.hxx>
#include <sfx2/StylePreviewRenderer.hxx>

#include <StyleList.hxx>

#include <vcl/virdev.hxx>
#include <basegfx/color/bcolortools.hxx>
#include <random>

using namespace css;
using namespace css::beans;
using namespace css::frame;
using namespace css::uno;

class TreeViewDropTarget final : public DropTargetHelper
{
private:
    StyleList& m_rParent;

public:
    TreeViewDropTarget(StyleList& rStyleList, weld::TreeView& rTreeView)
        : DropTargetHelper(rTreeView.get_drop_target())
        , m_rParent(rStyleList)
    {
    }

    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
    {
        return m_rParent.AcceptDrop(rEvt, *this);
    }

    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
    {
        return m_rParent.ExecuteDrop(rEvt);
    }
};

Color ColorHash(std::u16string_view rString)
{
    static constexpr auto aSaturationArray = std::to_array<sal_uInt16>({ 90, 75, 60 });
    static constexpr auto aBrightnessArray = std::to_array<sal_uInt16>({ 100, 80, 60 });
    static constexpr auto aTintOrShadeArray
        = std::to_array<sal_Int16>({ 1'500, 3'000, 4'500, 6'500, 7'500 });

    sal_uInt32 nStringHash = rtl_ustr_hashCode_WithLength(rString.data(), rString.length());

    // Twist the hash number with a RNG twister so we can get very different number even when the string hash
    // differs only slightly. For example "Heading 1" and "Heading 2" are very close, so we would get a color
    // that is very similar and with number quantization could result in the same color.
    std::mt19937 twister;
    twister.seed(nStringHash); // setting the hash for
    nStringHash = twister();

    double fHue = (nStringHash % 60) * 6;
    nStringHash = nStringHash / 60;

    double fSaturation = aSaturationArray[nStringHash % aSaturationArray.size()];
    nStringHash = nStringHash / aSaturationArray.size();

    double fBrightness = aBrightnessArray[nStringHash % aBrightnessArray.size()];
    nStringHash = nStringHash / aBrightnessArray.size();

    auto aColor = Color::HSBtoRGB(fHue, fSaturation, fBrightness);
    double fTintOrShade = aTintOrShadeArray[nStringHash % aTintOrShadeArray.size()];
    aColor.ApplyTintOrShade(fTintOrShade);

    return aColor;
}

namespace
{
// used to disallow the default character style in the styles spotlight character styles color map
std::optional<OUString> sDefaultCharStyleUIName;
}

// Constructor

StyleList::StyleList(weld::Builder* pBuilder, SfxBindings* pBindings,
                     SfxCommonTemplateDialog_Impl* Parent, weld::Container* pC,
                     const OUString& treeviewname, const OUString& flatviewname)
    : m_bHierarchical(false)
    , m_bAllowReParentDrop(false)
    , m_bNewByExampleDisabled(false)
    , m_bDontUpdate(false)
    , m_bTreeDrag(true)
    , m_bCanEdit(false)
    , m_bCanHide(true)
    , m_bCanShow(false)
    , m_bCanNew(true)
    , m_bUpdateFamily(false)
    , m_bCanDel(false)
    , m_bBindingUpdate(true)
    , m_pStyleSheetPool(nullptr)
    , m_nActFilter(0)
    , m_xFmtLb(pBuilder->weld_tree_view(flatviewname))
    , m_xTreeBox(pBuilder->weld_tree_view(treeviewname))
    , m_pCurObjShell(nullptr)
    , m_nActFamily(0xffff)
    , m_nAppFilter(SfxStyleSearchBits::Auto)
    , m_pParentDialog(Parent)
    , m_pBindings(pBindings)
    , m_Module(nullptr)
    , m_nModifier(0)
    , m_pContainer(pC)
{
    m_xFmtLb->set_help_id(HID_TEMPLATE_FMT);

    uno::Reference<frame::XFrame> xFrame
        = m_pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
    m_bModuleHasStylesSpotlightFeature
        = vcl::CommandInfoProvider::GetModuleIdentifier(xFrame) == "com.sun.star.text.TextDocument";
}

// Destructor

StyleList::~StyleList() {}

// Called in the destructor of Dialog
// Cleans up the StyleList individual components while closing the application
IMPL_LINK_NOARG(StyleList, Cleanup, void*, void)
{
    if (m_pStyleSheetPool)
        EndListening(*m_pStyleSheetPool);
    m_pStyleSheetPool = nullptr;
    m_xTreeView1DropTargetHelper.reset();
    m_xTreeView2DropTargetHelper.reset();
    m_xTreeBox.reset();
    m_xFmtLb.reset();
    pIdle.reset();
}

void StyleList::CreateContextMenu()
{
    if (m_bBindingUpdate)
    {
        m_pBindings->Invalidate(SID_STYLE_NEW, true);
        m_pBindings->Update(SID_STYLE_NEW);
        m_bBindingUpdate = false;
    }
    mxMenu.reset();
    mxMenuBuilder = Application::CreateBuilder(m_pContainer, u"sfx/ui/stylecontextmenu.ui"_ustr);
    mxMenu = mxMenuBuilder->weld_menu(u"menu"_ustr);
    mxMenu->set_sensitive(u"edit"_ustr, m_bCanEdit);
    mxMenu->set_sensitive(u"delete"_ustr, m_bCanDel);
    mxMenu->set_sensitive(u"new"_ustr, m_bCanNew);
    mxMenu->set_sensitive(u"hide"_ustr, m_bCanHide);
    mxMenu->set_sensitive(u"show"_ustr, m_bCanShow);

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
    {
        mxMenu->set_sensitive(u"edit"_ustr, false);
        mxMenu->set_sensitive(u"new"_ustr, false);
    }
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
    {
        const OUString aTemplName(GetSelectedEntry());
        if (aTemplName == "No List")
        {
            mxMenu->set_sensitive(u"edit"_ustr, false);
            mxMenu->set_sensitive(u"new"_ustr, false);
            mxMenu->set_sensitive(u"hide"_ustr, false);
        }
    }
}

IMPL_LINK_NOARG(StyleList, ReadResource, void*, size_t)
{
    // Read global user resource
    for (auto& i : m_pFamilyState)
        i.reset();

    SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
    m_pCurObjShell = pViewFrame->GetObjectShell();
    m_Module = m_pCurObjShell ? m_pCurObjShell->GetModule() : nullptr;
    if (m_Module)
        m_aStyleFamilies = m_Module->CreateStyleFamilies();

    m_nActFilter = 0xffff;

    if (m_pCurObjShell)
    {
        m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(m_pCurObjShell));
        if (0xffff == m_nActFilter)
        {
            m_nActFilter = m_pCurObjShell->GetAutoStyleFilterIndex();
        }
        if (m_bModuleHasStylesSpotlightFeature)
            sDefaultCharStyleUIName = getDefaultStyleName(SfxStyleFamily::Char);
    }
    size_t nCount = m_aStyleFamilies.size();
    m_pBindings->ENTERREGISTRATIONS();

    size_t i;
    for (i = 0; i < nCount; ++i)
    {
        sal_uInt16 nSlot = 0;
        switch (m_aStyleFamilies.at(i).GetFamily())
        {
            case SfxStyleFamily::Char:
                nSlot = SID_STYLE_FAMILY1;
                break;
            case SfxStyleFamily::Para:
                nSlot = SID_STYLE_FAMILY2;
                break;
            case SfxStyleFamily::Frame:
                nSlot = SID_STYLE_FAMILY3;
                break;
            case SfxStyleFamily::Page:
                nSlot = SID_STYLE_FAMILY4;
                break;
            case SfxStyleFamily::Pseudo:
                nSlot = SID_STYLE_FAMILY5;
                break;
            case SfxStyleFamily::Table:
                nSlot = SID_STYLE_FAMILY6;
                break;
            default:
                OSL_FAIL("unknown StyleFamily");
                break;
        }
        pBoundItems[i].reset(new SfxTemplateControllerItem(nSlot, *m_pParentDialog, *m_pBindings));
    }
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_WATERCAN, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_NEW_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_UPDATE_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_NEW, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_DRAGHIERARCHIE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_EDIT, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_DELETE, *m_pParentDialog, *m_pBindings));
    pBoundItems[i++].reset(
        new SfxTemplateControllerItem(SID_STYLE_FAMILY, *m_pParentDialog, *m_pBindings));
    m_pBindings->LEAVEREGISTRATIONS();

    for (; i < COUNT_BOUND_FUNC; ++i)
        pBoundItems[i] = nullptr;

    StartListening(*m_pBindings);

    for (i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++)
        m_pBindings->Update(i);

    return nCount;
}

void StyleList::EnableNewByExample(bool newByExampleDisabled)
{
    m_bNewByExampleDisabled = newByExampleDisabled;
}

void StyleList::FilterSelect(sal_uInt16 nActFilter, bool bsetFilter)
{
    m_nActFilter = nActFilter;
    if (bsetFilter)
    {
        SfxObjectShell* const pDocShell = m_aSaveSelection.Call(*this);
        SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
        m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
        if (pOldStyleSheetPool != m_pStyleSheetPool)
        {
            if (pOldStyleSheetPool)
                EndListening(*pOldStyleSheetPool);
            if (m_pStyleSheetPool)
                StartListening(*m_pStyleSheetPool);
        }
    }
    UpdateStyles(StyleFlags::UpdateFamilyList);
}

IMPL_LINK(StyleList, SetFamily, sal_uInt16, nId, void)
{
    if (m_nActFamily != 0xFFFF)
        m_pParentDialog->CheckItem(OUString::number(m_nActFamily), false);
    m_nActFamily = nId;
    if (nId != 0xFFFF)
    {
        m_bUpdateFamily = true;
    }
}

void StyleList::InvalidateBindings()
{
    m_pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
    m_pBindings->Update(SID_STYLE_NEW_BY_EXAMPLE);
    m_pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
    m_pBindings->Update(SID_STYLE_UPDATE_BY_EXAMPLE);
    m_pBindings->Invalidate(SID_STYLE_WATERCAN, true);
    m_pBindings->Update(SID_STYLE_WATERCAN);
    m_pBindings->Invalidate(SID_STYLE_NEW, true);
    m_pBindings->Update(SID_STYLE_NEW);
    m_pBindings->Invalidate(SID_STYLE_DRAGHIERARCHIE, true);
    m_pBindings->Update(SID_STYLE_DRAGHIERARCHIE);
}

void StyleList::Initialize()
{
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
    m_pBindings->Update(SID_STYLE_FAMILY);

    m_xFmtLb->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
    m_xFmtLb->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
    m_xFmtLb->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
    m_xFmtLb->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
    m_xFmtLb->connect_popup_menu(LINK(this, StyleList, PopupFlatMenuHdl));
    m_xFmtLb->connect_key_press(LINK(this, StyleList, KeyInputHdl));
    m_xFmtLb->set_selection_mode(SelectionMode::Multiple);
    m_xTreeBox->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
    m_xTreeBox->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
    m_xTreeBox->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
    m_xTreeBox->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
    m_xTreeBox->connect_popup_menu(LINK(this, StyleList, PopupTreeMenuHdl));
    m_xTreeBox->connect_key_press(LINK(this, StyleList, KeyInputHdl));
    m_xTreeBox->connect_drag_begin(LINK(this, StyleList, DragBeginHdl));
    m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xFmtLb));
    m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xTreeBox));

    m_pParentDialog->connect_stylelist_read_resource(LINK(this, StyleList, ReadResource));
    m_pParentDialog->connect_stylelist_clear(LINK(this, StyleList, Clear));
    m_pParentDialog->connect_stylelist_cleanup(LINK(this, StyleList, Cleanup));
    m_pParentDialog->connect_stylelist_execute_drop(LINK(this, StyleList, ExecuteDrop));
    m_pParentDialog->connect_stylelist_execute_new_menu(
        LINK(this, StyleList, NewMenuExecuteAction));
    m_pParentDialog->connect_stylelist_for_watercan(LINK(this, StyleList, IsSafeForWaterCan));
    m_pParentDialog->connect_stylelist_has_selected_style(LINK(this, StyleList, HasSelectedStyle));
    m_pParentDialog->connect_stylelist_update_style_dependents(
        LINK(this, StyleList, UpdateStyleDependents));
    m_pParentDialog->connect_stylelist_enable_tree_drag(LINK(this, StyleList, EnableTreeDrag));
    m_pParentDialog->connect_stylelist_enable_delete(LINK(this, StyleList, EnableDelete));
    m_pParentDialog->connect_stylelist_set_water_can_state(LINK(this, StyleList, SetWaterCanState));
    m_pParentDialog->connect_set_family(LINK(this, StyleList, SetFamily));

    int nTreeHeight = m_xFmtLb->get_height_rows(8);
    m_xFmtLb->set_size_request(-1, nTreeHeight);
    m_xTreeBox->set_size_request(-1, nTreeHeight);

    m_xFmtLb->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
    m_xFmtLb->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
    m_xTreeBox->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
    m_xTreeBox->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
    bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
    m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
    m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);

    m_xFmtLb->set_visible(!m_bHierarchical);
    m_xTreeBox->set_visible(m_bHierarchical);
    Update();
}

void StyleList::UpdateFamily()
{
    m_bUpdateFamily = false;

    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
    SfxViewFrame* pViewFrame = pDispat->GetFrame();
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();

    SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
    m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
    if (pOldStyleSheetPool != m_pStyleSheetPool)
    {
        if (pOldStyleSheetPool)
            EndListening(*pOldStyleSheetPool);
        if (m_pStyleSheetPool)
            StartListening(*m_pStyleSheetPool);
    }

    m_bTreeDrag = true;
    m_bCanNew = m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
    m_pParentDialog->EnableNew(m_bCanNew, this);
    m_bTreeDrag = true;
    if (m_pStyleSheetPool)
    {
        if (!m_xTreeBox->get_visible())
            UpdateStyles(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
        else
        {
            UpdateStyles(StyleFlags::UpdateFamily);
            FillTreeBox(GetActualFamily());
        }
    }

    InvalidateBindings();
}

bool StyleList::EnableExecute()
{
    return m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
}

void StyleList::connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink)
{
    m_aLoadFactoryStyleFilter = rLink;
}

void StyleList::connect_SaveSelection(const Link<StyleList&, SfxObjectShell*> rLink)
{
    m_aSaveSelection = rLink;
}

/** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
    create a style out of the current selection.
*/

sal_Int8 StyleList::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
{
    if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
    {
        // special case: page styles are allowed to create new styles by example
        // but not allowed to be created by drag and drop
        if (GetActualFamily() == SfxStyleFamily::Page || m_bNewByExampleDisabled)
            return DND_ACTION_NONE;
        else
            return DND_ACTION_COPY;
    }
    // to enable the autoscroll when we're close to the edges
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
    return DND_ACTION_MOVE;
}

// handles drop of content in treeview when creating a new style
IMPL_LINK(StyleList, ExecuteDrop, const ExecuteDropEvent&, rEvt, sal_Int8)
{
    SfxObjectShell* pDocShell = m_pCurObjShell;
    if (pDocShell)
    {
        TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
        sal_uInt32 nFormatCount = aHelper.GetFormatCount();

        sal_Int8 nRet = DND_ACTION_NONE;

        bool bFormatFound = false;

        for (sal_uInt32 i = 0; i < nFormatCount; ++i)
        {
            SotClipboardFormatId nId = aHelper.GetFormat(i);
            TransferableObjectDescriptor aDesc;

            if (aHelper.GetTransferableObjectDescriptor(nId, aDesc))
            {
                if (aDesc.maClassName == pDocShell->GetFactory().GetClassId())
                {
                    Application::PostUserEvent(
                        LINK(m_pParentDialog, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop),
                        this);

                    bFormatFound = true;
                    nRet = rEvt.mnAction;
                    break;
                }
            }
        }

        if (bFormatFound)
            return nRet;
    }

    if (!m_xTreeBox->get_visible())
        return DND_ACTION_NONE;

    if (!m_bAllowReParentDrop)
        return DND_ACTION_NONE;

    // otherwise if we're dragging with the treeview to set a new parent of the dragged style
    weld::TreeView* pSource = m_xTreeBox->get_drag_source();
    // only dragging within the same widget allowed
    if (!pSource || pSource != m_xTreeBox.get())
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xSource(m_xTreeBox->make_iterator());
    if (!m_xTreeBox->get_selected(xSource.get()))
        return DND_ACTION_NONE;

    std::unique_ptr<weld::TreeIter> xTarget(m_xTreeBox->make_iterator());
    if (!m_xTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
    {
        // if nothing under the mouse, use the last row
        int nChildren = m_xTreeBox->n_children();
        if (!nChildren)
            return DND_ACTION_NONE;
        if (!m_xTreeBox->get_iter_first(*xTarget)
            || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
            return DND_ACTION_NONE;
        while (m_xTreeBox->get_row_expanded(*xTarget))
        {
            nChildren = m_xTreeBox->iter_n_children(*xTarget);
            if (!m_xTreeBox->iter_children(*xTarget)
                || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
                return DND_ACTION_NONE;
        }
    }
    OUString aTargetStyle = m_xTreeBox->get_text(*xTarget);
    DropHdl(m_xTreeBox->get_text(*xSource), aTargetStyle);
    m_xTreeBox->unset_drag_dest_row();
    FillTreeBox(GetActualFamily());
    m_pParentDialog->SelectStyle(aTargetStyle, false, *this);
    return DND_ACTION_NONE;
}

IMPL_LINK_NOARG(StyleList, NewMenuExecuteAction, void*, void)
{
    if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
        return;

    const SfxStyleFamily eFam = GetFamilyItem()->GetFamily();
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
    if (pItem && m_nActFilter != 0xffff)
        nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
    if (nFilter == SfxStyleSearchBits::Auto// automatic
        nFilter = m_nAppFilter;

    // why? : FloatingWindow must not be parent of a modal dialog
    SfxNewStyleDlg aDlg(m_pContainer, *m_pStyleSheetPool, eFam);
    auto nResult = aDlg.run();
    if (nResult == RET_OK)
    {
        const OUString aTemplName(aDlg.GetName());
        m_pParentDialog->Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, aTemplName, u""_ustr,
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
                                      nFilter);
        UpdateFamily();
        m_aUpdateFamily.Call(*this);
    }
}

void StyleList::DropHdl(const OUString& rStyle, const OUString& rParent)
{
    m_bDontUpdate = true;
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    const SfxStyleFamily eFam = pItem->GetFamily();
    if (auto pStyle = m_pStyleSheetPool->Find(rStyle, eFam))
        pStyle->SetParent(rParent);
    m_bDontUpdate = false;
}

void StyleList::PrepareMenu(const Point& rPos)
{
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
    if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
    {
        pTreeView->unselect_all();
        pTreeView->set_cursor(*xIter);
        pTreeView->select(*xIter);
    }
    FmtSelectHdl(*pTreeView);
}

/** Internal structure for the establishment of the hierarchical view */
namespace
{
class StyleTree_Impl;
}

typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;

namespace
{
class StyleTree_Impl
{
private:
    OUString aName;
    OUString aParent;
    sal_Int32 nSpotlightId;
    StyleTreeArr_Impl pChildren;

public:
    bool HasParent() const { return !aParent.isEmpty(); }

    StyleTree_Impl(OUString _aName, OUString _aParent, sal_Int32 _nSpotlightId)
        : aName(std::move(_aName))
        , aParent(std::move(_aParent))
        , nSpotlightId(_nSpotlightId)
        , pChildren(0)
    {
    }

    const OUString& getName() const { return aName; }
    const OUString& getParent() const { return aParent; }
    sal_Int32 getSpotlightId() const { return nSpotlightId; }
    StyleTreeArr_Impl& getChildren() { return pChildren; }
};
}

static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
{
    const comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
    styleFinder.reserve(rArr.size());
    for (const auto& pEntry : rArr)
    {
        styleFinder.emplace(pEntry->getName(), pEntry.get());
    }

    // Arrange all under their Parents
    for (auto& pEntry : rArr)
    {
        if (!pEntry->HasParent())
            continue;
        auto it = styleFinder.find(pEntry->getParent());
        if (it != styleFinder.end())
        {
            StyleTree_Impl* pCmp = it->second;
            // Insert child entries sorted
            auto iPos = std::lower_bound(
                pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
                [&aSorter](std::unique_ptr<StyleTree_Impl> const& pEntry1,
                           std::unique_ptr<StyleTree_Impl> const& pEntry2) {
                    return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
                });
            pCmp->getChildren().insert(iPos, std::move(pEntry));
        }
    }

    // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
    std::erase_if(rArr, [](std::unique_ptr<StyleTree_Impl> const& pEntry) { return !pEntry; });

    // tdf#91106 sort top level styles
    std::sort(rArr.begin(), rArr.end());
    std::sort(rArr.begin(), rArr.end(),
              [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const& pEntry1,
                                   std::unique_ptr<StyleTree_Impl> const& pEntry2) {
                  if (pEntry2->getName() == aUIName)
                      return false;
                  if (pEntry1->getName() == aUIName)
                      return true// default always first
                  return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
              });
}

static bool IsExpanded_Impl(const std::vector<OUString>& rEntries, std::u16string_view rStr)
{
    for (const auto& rEntry : rEntries)
    {
        if (rEntry == rStr)
            return true;
    }
    return false;
}

static void lcl_Update(weld::TreeView& rTreeView, const weld::TreeIter& rIter,
                       const StyleTree_Impl& rEntry, SfxStyleFamily eFam, SfxViewShell* pViewSh)
{
    const OUString& rName = rEntry.getName();

    Color aColor = ColorHash(rName);

    // For kit keep the id used for spotlight/number-image for a style stable
    // regardless of the selection mode of the style panel, so multiple views
    // on a document all share the same id for a style.
    sal_Int32 nSpotlightId;
    if (comphelper::LibreOfficeKit::isActive())
        nSpotlightId = rEntry.getSpotlightId();
    else
    {
        StylesSpotlightColorMap& rColorMap = (eFam == SfxStyleFamily::Para)
                                                 ? pViewSh->GetStylesSpotlightParaColorMap()
                                                 : pViewSh->GetStylesSpotlightCharColorMap();
        nSpotlightId = rColorMap.size();
        rColorMap[rName] = std::pair(aColor, nSpotlightId);
    }

    if (eFam == SfxStyleFamily::Char)
    {
        // don't show a color or number for default character style 'No Character Style' entry
        if (rName == sDefaultCharStyleUIName.value() /*"No Character Style"*/)
        {
            rTreeView.set_id(rIter, rName);
            rTreeView.set_text(rIter, rName);
            return;
        }
    }

    // draw the color rectangle and number image
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    Size aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
    ScopedVclPtrInstance<VirtualDevice> xDevice;
    xDevice->SetOutputSize(aImageSize);
    xDevice->SetFillColor(aColor);
    const tools::Rectangle aRect(Point(0, 0), aImageSize);
    xDevice->DrawRect(aRect);
    // In kit mode, unused styles are -1, so we can just skip the number image for those
    if (nSpotlightId != -1)
    {
        xDevice->SetTextColor(COL_BLACK);
        xDevice->DrawText(aRect, OUString::number(nSpotlightId),
                          DrawTextFlags::Center | DrawTextFlags::VCenter);
    }

    rTreeView.set_id(rIter, rName);
    rTreeView.set_text(rIter, rName);
    rTreeView.set_image(rIter, *xDevice, 0);
}

static void FillBox_Impl(weld::TreeView& rBox, StyleTreeArr_Impl& rTreeArray,
                         SfxStyleFamily eStyleFamily, const weld::TreeIter* pParent,
                         bool blcl_insert, SfxViewShell* pViewShell,
                         SfxStyleSheetBasePool* pStyleSheetPool)
{
    if (rTreeArray.empty())
        return;
    rBox.bulk_insert_for_each(rTreeArray.size(),
                              [&rTreeArray, blcl_insert, pStyleSheetPool, eStyleFamily, &rBox,
                               pViewShell](weld::TreeIter& rIter, int i) {
                                  StyleTree_Impl* pChildEntry = rTreeArray[i].get();
                                  const OUString& rChildName = pChildEntry->getName();
                                  if (blcl_insert)
                                  {
                                      const SfxStyleSheetBase* pStyle = nullptr;
                                      if (pStyleSheetPool)
                                          pStyle = pStyleSheetPool->Find(rChildName, eStyleFamily);
                                      if (pStyle && pStyle->IsUsed())
                                          lcl_Update(rBox, rIter, *pChildEntry, eStyleFamily,
                                                     pViewShell);
                                      else
                                      {
                                          rBox.set_id(rIter, rChildName);
                                          rBox.set_text(rIter, rChildName);
                                      }
                                  }
                                  else
                                  {
                                      rBox.set_id(rIter, rChildName);
                                      rBox.set_text(rIter, rChildName);
                                  }
                              },
                              pParent, nullptr, /*bGoingToSetText*/ true);

    std::unique_ptr<weld::TreeIter> xChildParentIter = rBox.make_iterator(pParent);
    if (!pParent)
        (void)rBox.get_iter_first(*xChildParentIter);
    else
        (void)rBox.iter_children(*xChildParentIter);
    for (size_t i = 0; i < rTreeArray.size(); ++i)
    {
        FillBox_Impl(rBox, rTreeArray[i]->getChildren(), eStyleFamily, xChildParentIter.get(),
                     blcl_insert, pViewShell, pStyleSheetPool);
        (void)rBox.iter_next_sibling(*xChildParentIter);
    }
}

namespace SfxTemplate
{
// converts from SFX_STYLE_FAMILY Ids to 1-6
static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
{
    switch (nFamily)
    {
        case SfxStyleFamily::Char:
            return 1;
        case SfxStyleFamily::Para:
            return 2;
        case SfxStyleFamily::Frame:
            return 3;
        case SfxStyleFamily::Page:
            return 4;
        case SfxStyleFamily::Pseudo:
            return 5;
        case SfxStyleFamily::Table:
            return 6;
        default:
            return 0xffff;
    }
}
// converts from 1-6 to SFX_STYLE_FAMILY Ids
static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
{
    switch (nId)
    {
        case 1:
            return SfxStyleFamily::Char;
        case 2:
            return SfxStyleFamily::Para;
        case 3:
            return SfxStyleFamily::Frame;
        case 4:
            return SfxStyleFamily::Page;
        case 5:
            return SfxStyleFamily::Pseudo;
        case 6:
            return SfxStyleFamily::Table;
        default:
            return SfxStyleFamily::All;
    }
}
}

sal_uInt16 StyleList::StyleNrToInfoOffset(sal_uInt16 nId)
{
    const SfxStyleFamilyItem& rItem = m_aStyleFamilies.at(nId);
    return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()) - 1;
}

// Helper function: Access to the current family item
const SfxStyleFamilyItem* StyleList::GetFamilyItem() const
{
    const size_t nCount = m_aStyleFamilies.size();
    for (size_t i = 0; i < nCount; ++i)
    {
        const SfxStyleFamilyItem& rItem = m_aStyleFamilies.at(i);
        sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
        if (nId == m_nActFamily)
            return &rItem;
    }
    return nullptr;
}

void StyleList::GetSelectedStyle() const
{
    const OUString aTemplName(GetSelectedEntry());
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
}

// Used to get the current selected entry in visible treeview
OUString StyleList::GetSelectedEntry() const
{
    OUString aRet;
    if (m_xTreeBox->get_visible())
        aRet = m_xTreeBox->get_selected_text();
    else
        aRet = m_xFmtLb->get_selected_text();
    return aRet;
}

/**
 * Is it safe to show the water-can / fill icon. If we've a
 * hierarchical widget - we have only single select, otherwise
 * we need to check if we have a multi-selection. We either have
 * a m_xTreeBox showing or an m_xFmtLb (which we hide when not shown)
 */

IMPL_LINK_NOARG(StyleList, IsSafeForWaterCan, void*, bool)
{
    if (m_xTreeBox->get_visible())
        return m_xTreeBox->get_selected_index() != -1;
    else
        return m_xFmtLb->count_selected_rows() == 1;
}

IMPL_LINK(StyleList, SetWaterCanState, const SfxBoolItem*, pItem, void)
{
    size_t nCount = m_aStyleFamilies.size();
    m_pBindings->EnterRegistrations();
    for (size_t n = 0; n < nCount; n++)
    {
        SfxControllerItem* pCItem = pBoundItems[n].get();
        bool bChecked = pItem && pItem->GetValue();
        if (pCItem->IsBound() == bChecked)
        {
            if (!bChecked)
                pCItem->ReBind();
            else
                pCItem->UnBind();
        }
    }
    m_pBindings->LeaveRegistrations();
}

void StyleList::FamilySelect(sal_uInt16 nEntry, bool bRefresh)
{
    if (bRefresh)
    {
        bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
        m_xFmtLb->clear();
        m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
        m_xTreeBox->clear();
        m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);
    }
    m_nActFamily = nEntry;
    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
    SfxUInt16Item const aItem(SID_STYLE_FAMILY,
                              static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
    pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
    m_pBindings->Update(SID_STYLE_FAMILY);
    UpdateFamily();
    m_aUpdateFamily.Call(*this);
}

// It selects the style in treeview
// bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
// styles, bIsCallBack will be true for it.
void StyleList::SelectStyle(const OUString& rStr, bool bIsCallback)
{
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return;
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(rStr, eFam);
    if (pStyle)
    {
        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
        m_pParentDialog->EnableEdit(bReadWrite, this);
        m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsHidden() && !pStyle->IsUsed(), this);
        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
    }
    else
    {
        m_pParentDialog->EnableEdit(falsethis);
        m_pParentDialog->EnableHide(falsethis);
        m_pParentDialog->EnableShow(falsethis);
    }

    if (bIsCallback)
        return;

    if (m_xTreeBox->get_visible())
    {
        if (!rStr.isEmpty())
        {
            std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
            bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
            while (bEntry)
            {
                if (m_xTreeBox->get_text(*xEntry) == rStr)
                {
                    m_xTreeBox->scroll_to_row(*xEntry);
                    m_xTreeBox->select(*xEntry);
                    break;
                }
                bEntry = m_xTreeBox->iter_next(*xEntry);
            }
        }
        else if (eFam == SfxStyleFamily::Pseudo)
        {
            std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
            if (m_xTreeBox->get_iter_first(*xEntry))
            {
                m_xTreeBox->scroll_to_row(*xEntry);
                m_xTreeBox->select(*xEntry);
            }
        }
        else
            m_xTreeBox->unselect_all();
    }
    else
    {
        bool bSelect = !rStr.isEmpty();
        if (bSelect)
        {
            std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
            bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
            while (bEntry && m_xFmtLb->get_text(*xEntry) != rStr)
                bEntry = m_xFmtLb->iter_next(*xEntry);
            if (!bEntry)
                bSelect = false;
            else
            {
                if (!m_xFmtLb->is_selected(*xEntry))
                {
                    m_xFmtLb->unselect_all();
                    m_xFmtLb->scroll_to_row(*xEntry);
                    m_xFmtLb->select(*xEntry);
                }
            }
        }

        if (!bSelect)
        {
            m_xFmtLb->unselect_all();
            m_pParentDialog->EnableEdit(falsethis);
            m_pParentDialog->EnableHide(falsethis);
            m_pParentDialog->EnableShow(falsethis);
        }
    }
}

static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& ;rEntries)
{
    std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
    if (rBox.get_iter_first(*xEntry))
    {
        do
        {
            if (rBox.get_row_expanded(*xEntry))
                rEntries.push_back(rBox.get_text(*xEntry));
        } while (rBox.iter_next(*xEntry));
    }
}

IMPL_LINK(StyleList, EnableTreeDrag, bool, m_bEnable, void)
{
    if (m_pStyleSheetPool)
    {
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        SfxStyleSheetBase* pStyle = pItem ? m_pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
        m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bEnable;
    }
    m_bTreeDrag = m_bEnable;
}

// Fill the treeview

void StyleList::FillTreeBox(SfxStyleFamily eFam)
{
    assert(m_xTreeBox && "FillTreeBox() without treebox");
    if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
        return;

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return;

    StyleTreeArr_Impl aArr;
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, SfxStyleSearchBits::All);

    m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bTreeDrag;

    while (pStyle)
    {
        if (pStyle->IsHidden()
            && (pStyle->GetFamily() == SfxStyleFamily::Page
                || pStyle->GetFamily() == SfxStyleFamily::Pseudo
                || pStyle->GetFamily() == SfxStyleFamily::Table))
            ;
        else
        {
            StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent(),
                                                      pStyle->GetSpotlightId());
            aArr.emplace_back(pNew);
        }
        pStyle = m_pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);
    MakeTree_Impl(aArr, aUIName);
    std::vector<OUString> aEntries;
    MakeExpanded_Impl(*m_xTreeBox, aEntries);
    m_xTreeBox->freeze();
    m_xTreeBox->clear();
    const sal_uInt16 nCount = aArr.size();

    SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
    StylesSpotlightColorMap* pSpotlightColorMap = nullptr;
    bool bOrigMapHasEntries = false;
    if (pViewShell && m_bModuleHasStylesSpotlightFeature)
    {
        if (eFam == SfxStyleFamily::Para)
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightParaColorMap();
        else if (eFam == SfxStyleFamily::Char)
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightCharColorMap();
    }

    if (pSpotlightColorMap && !pSpotlightColorMap->empty())
    {
        bOrigMapHasEntries = true;
        pSpotlightColorMap->clear();
    }

    bool blcl_insert = pViewShell && m_bModuleHasStylesSpotlightFeature
                       && ((eFam == SfxStyleFamily::Para && m_bSpotlightParaStyles)
                           || (eFam == SfxStyleFamily::Char && m_bSpotlightCharStyles));

    FillBox_Impl(*m_xTreeBox, aArr, eFam, nullptr, blcl_insert, pViewShell, m_pStyleSheetPool);
    for (sal_uInt16 i = 0; i < nCount; ++i)
        aArr[i].reset();

    m_xTreeBox->columns_autosize();

    m_pParentDialog->EnableItem(u"watercan"_ustr, false);

    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();

    m_xTreeBox->thaw();

    // make view update
    if (pViewShell && pSpotlightColorMap && (!pSpotlightColorMap->empty() || bOrigMapHasEntries))
        static_cast<SfxListener*>(pViewShell)
            ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesSpotlightModified));

    std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
    bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
    if (bEntry && nCount)
        m_xTreeBox->expand_row(*xEntry);

    while (bEntry)
    {
        if (IsExpanded_Impl(aEntries, m_xTreeBox->get_text(*xEntry)))
            m_xTreeBox->expand_row(*xEntry);
        bEntry = m_xTreeBox->iter_next(*xEntry);
    }

    OUString aStyle;
    if (pState) // Select current entry
        aStyle = pState->GetStyleName();
    m_pParentDialog->SelectStyle(aStyle, false, *this);
    EnableDelete(nullptr);
}

static OUString lcl_GetStyleFamilyName(SfxStyleFamily nFamily)
{
    if (nFamily == SfxStyleFamily::Char)
        return u"CharacterStyles"_ustr;
    if (nFamily == SfxStyleFamily::Para)
        return u"ParagraphStyles"_ustr;
    if (nFamily == SfxStyleFamily::Page)
        return u"PageStyles"_ustr;
    if (nFamily == SfxStyleFamily::Table)
        return u"TableStyles"_ustr;
    if (nFamily == SfxStyleFamily::Pseudo)
        return u"NumberingStyles"_ustr;
    return OUString();
}

OUString StyleList::getDefaultStyleName(const SfxStyleFamily eFam)
{
    OUString sDefaultStyle;
    OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
    if (aFamilyName == "TableStyles")
        sDefaultStyle = "Default Style";
    else if (aFamilyName == "NumberingStyles")
        sDefaultStyle = "No List";
    else
        sDefaultStyle = "Standard";
    uno::Reference<style::XStyleFamiliesSupplier> xModel(m_pCurObjShell->GetModel(),
                                                         uno::UNO_QUERY);
    OUString aUIName;
    try
    {
        uno::Reference<container::XNameAccess> xStyles;
        uno::Reference<container::XNameAccess> xCont = xModel->getStyleFamilies();
        xCont->getByName(aFamilyName) >>= xStyles;
        uno::Reference<beans::XPropertySet> xInfo;
        xStyles->getByName(sDefaultStyle) >>= xInfo;
        xInfo->getPropertyValue(u"DisplayName"_ustr) >>= aUIName;
    }
    catch (const uno::Exception&)
    {
    }
    return aUIName;
}

SfxStyleFamily StyleList::GetActualFamily() const
{
    const SfxStyleFamilyItem* pFamilyItem = GetFamilyItem();
    if (!pFamilyItem || m_nActFamily == 0xffff)
        return SfxStyleFamily::Para;
    else
        return pFamilyItem->GetFamily();
}

IMPL_LINK_NOARG(StyleList, HasSelectedStyle, void*, bool)
{
    return m_xTreeBox->get_visible() ? m_xTreeBox->get_selected_index() != -1
                                     : m_xFmtLb->count_selected_rows() != 0;
}

IMPL_LINK_NOARG(StyleList, UpdateStyleDependents, void*, void)
{
    // Trigger Help PI. Only when the watercan is on
    if (m_nActFamily != 0xffff && m_pParentDialog->IsCheckedItem(u"watercan"_ustr) &&
        // only if that region is allowed
        nullptr != m_pFamilyState[m_nActFamily - 1] && IsSafeForWaterCan(nullptr))
    {
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, *this);
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, GetSelectedEntry(), u""_ustr,
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
    }
}

// Comes into action when the current style is changed
void StyleList::UpdateStyles(StyleFlags nFlags)
{
    OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
    {
        // Is the case for the template catalog
        const size_t nFamilyCount = m_aStyleFamilies.size();
        size_t n;
        for (n = 0; n < nFamilyCount; n++)
            if (m_pFamilyState[StyleNrToInfoOffset(n)])
                break;
        if (n == nFamilyCount)
            // It happens sometimes, God knows why
            return;
        m_nAppFilter = m_pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
        m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
        pItem = GetFamilyItem();
    }

    const SfxStyleFamily eFam = pItem->GetFamily();

    SfxStyleSearchBits nFilter(m_nActFilter < pItem->GetFilterList().size()
                                   ? pItem->GetFilterList()[m_nActFilter].nFlags
                                   : SfxStyleSearchBits::Auto);
    if (nFilter == SfxStyleSearchBits::Auto// automatic
        nFilter = m_nAppFilter;

    OSL_ENSURE(m_pStyleSheetPool, "no StyleSheetPool");
    if (!m_pStyleSheetPool)
        return;

    m_aUpdateStyles.Call(nFlags);

    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, nFilter);

    std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
    std::vector<StyleTree_Impl> aStyles;

    comphelper::string::NaturalStringSorter aSorter(
        ::comphelper::getProcessComponentContext(),
        Application::GetSettings().GetLanguageTag().getLocale());

    while (pStyle)
    {
        aStyles.emplace_back(pStyle->GetName(), pStyle->GetParent(), pStyle->GetSpotlightId());
        pStyle = m_pStyleSheetPool->Next();
    }
    OUString aUIName = getDefaultStyleName(eFam);

    // Paradoxically, with a list and non-Latin style names,
    // sorting twice is faster than sorting once.
    // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
    // Then the second sort needs to call its (much more expensive) comparator less often.
    std::sort(aStyles.begin(), aStyles.end(),
              [](const StyleTree_Impl& rLHS, const StyleTree_Impl& rRHS) {
                  return rLHS.getName() < rRHS.getName();
              });
    std::sort(aStyles.begin(), aStyles.end(),
              [&aSorter, &aUIName](const StyleTree_Impl& rLHSS, const StyleTree_Impl&&nbsp;rRHSS) {
                  const OUString& rLHS = rLHSS.getName();
                  const OUString& rRHS = rRHSS.getName();
                  if (rRHS == aUIName)
                      return false;
                  if (rLHS == aUIName)
                      return true// default always first
                  return aSorter.compare(rLHS, rRHS) < 0;
              });

    // Fill the display box
    m_xFmtLb->freeze();
    m_xFmtLb->clear();

    SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
    StylesSpotlightColorMap* pSpotlightColorMap = nullptr;
    bool bOrigMapHasEntries = false;
    if (pViewShell && m_bModuleHasStylesSpotlightFeature)
    {
        if (eFam == SfxStyleFamily::Para)
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightParaColorMap();
        else if (eFam == SfxStyleFamily::Char)
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightCharColorMap();
    }

    if (pSpotlightColorMap && !pSpotlightColorMap->empty())
    {
        bOrigMapHasEntries = true;
        pSpotlightColorMap->clear();
    }

    size_t nCount = aStyles.size();

    if (pViewShell && m_bModuleHasStylesSpotlightFeature
        && ((eFam == SfxStyleFamily::Para && m_bSpotlightParaStyles)
            || (eFam == SfxStyleFamily::Char && m_bSpotlightCharStyles)))
    {
        m_xFmtLb->bulk_insert_for_each(
            nCount,
            [this, &aStyles, eFam, pViewShell](weld::TreeIter& rIter, int nIdx) {
                const OUString& rName = aStyles[nIdx].getName();
                auto pChildStyle = m_pStyleSheetPool->Find(rName, eFam);
                if (pChildStyle && pChildStyle->IsUsed())
                    lcl_Update(*m_xFmtLb, rIter, aStyles[nIdx], eFam, pViewShell);
                else
                {
                    m_xFmtLb->set_id(rIter, rName);
                    m_xFmtLb->set_text(rIter, rName);
                }
            },
            nullptr, nullptr, /*bGoingToSetText*/ true);
    }
    else
    {
        m_xFmtLb->bulk_insert_for_each(nCount,
                                       [this, &aStyles](weld::TreeIter& rIter, int nIdx) {
                                           const OUString& rName = aStyles[nIdx].getName();
                                           m_xFmtLb->set_id(rIter, rName);
                                           m_xFmtLb->set_text(rIter, rName);
                                       },
                                       nullptr, nullptr, /*bGoingToSetText*/ true);
    }

    m_xFmtLb->columns_autosize();

    m_xFmtLb->thaw();

    // make view update
    if (pViewShell && pSpotlightColorMap && (!pSpotlightColorMap->empty() || bOrigMapHasEntries))
        static_cast<SfxListener*>(pViewShell)
            ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesSpotlightModified));

    // Selects the current style if any
    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
    OUString aStyle;
    if (pState)
        aStyle = pState->GetStyleName();
    m_pParentDialog->SelectStyle(aStyle, false, *this);
    EnableDelete(nullptr);
}

void StyleList::SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem)
{
    sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
    m_pFamilyState[nIdx].reset();
    if (pItem)
        m_pFamilyState[nIdx].reset(new SfxTemplateItem(*pItem));
    m_bUpdateFamily = true;
}

void StyleList::SetHierarchical()
{
    m_bHierarchical = true;
    const OUString aSelectEntry(GetSelectedEntry());
    m_xFmtLb->hide();
    FillTreeBox(GetActualFamily());
    m_pParentDialog->SelectStyle(aSelectEntry, false, *this);
    m_xTreeBox->show();
}

void StyleList::SetFilterControlsHandle()
{
    m_xTreeBox->hide();
    m_xFmtLb->show();
    m_bHierarchical = false;
}

// Handler for the New-Buttons
void StyleList::NewHdl()
{
    if (m_nActFamily == 0xffff
        || !(m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1))
        return;

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    const SfxStyleFamily eFam = pItem->GetFamily();
    SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
    if (m_nActFilter != 0xffff)
        nMask = pItem->GetFilterList()[m_nActFilter].nFlags;
    if (nMask == SfxStyleSearchBits::Auto// automatic
        nMask = m_nAppFilter;

    m_pParentDialog->Execute_Impl(SID_STYLE_NEW, u""_ustr, GetSelectedEntry(),
                                  static_cast<sal_uInt16>(eFam), *this, nMask);
}

// Handler for the edit-Buttons
void StyleList::EditHdl()
{
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
    {
        sal_uInt16 nFilter = m_nActFilter;
        OUString aTemplName(GetSelectedEntry());
        GetSelectedStyle(); // -Wall required??
        m_pParentDialog->Execute_Impl(SID_STYLE_EDIT, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
                                      SfxStyleSearchBits::Auto, &nFilter);
    }
}

// Handler for the Delete-Buttons
void StyleList::DeleteHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    bool bUsedStyle = false// one of the selected styles are used in the document?

    std::vector<std::unique_ptr<weld::TreeIter>> aList;
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    const SfxStyleFamilyItem* pItem = GetFamilyItem();

    OUStringBuffer aMsg(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));

    pTreeView->selected_foreach(
        [this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry) {
            aList.emplace_back(pTreeView->make_iterator(&rEntry));
            // check the style is used or not
            const OUString aTemplName(pTreeView->get_text(rEntry));

            SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());

            if (pStyle->IsUsed()) // pStyle is in use in the document?
            {
                if (bUsedStyle) // add a separator for the second and later styles
                    aMsg.append(", ");
                aMsg.append(aTemplName);
                bUsedStyle = true;
            }

            return false;
        });

    bool aApproved = false;

    // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
    if (bUsedStyle)
    {
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
            pTreeView, VclMessageType::Question, VclButtonsType::YesNo, aMsg.makeStringAndClear()));
        aApproved = xBox->run() == RET_YES;
    }

    // if there are no used styles selected or the user approved the changes
    if (bUsedStyle && !aApproved)
        return;

    for (auto const& elem : aList)
    {
        const OUString aTemplName(pTreeView->get_text(*elem));
        m_bDontUpdate = true// To prevent the Treelistbox to shut down while deleting
        m_pParentDialog->Execute_Impl(SID_STYLE_DELETE, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        if (m_xTreeBox->get_visible())
        {
            weld::RemoveParentKeepChildren(*m_xTreeBox, *elem);
            m_bDontUpdate = false;
        }
    }
    m_bDontUpdate = false// if everything is deleted set m_bDontUpdate back to false
    UpdateStyles(StyleFlags::UpdateFamilyList); // and force-update the list
}

void StyleList::HideHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
        OUString aTemplName = pTreeView->get_text(rEntry);

        m_pParentDialog->Execute_Impl(SID_STYLE_HIDE, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        return false;
    });
}

void StyleList::ShowHdl()
{
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
        return;

    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
        OUString aTemplName = pTreeView->get_text(rEntry);

        m_pParentDialog->Execute_Impl(SID_STYLE_SHOW, aTemplName, OUString(),
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);

        return false;
    });
}

IMPL_LINK_NOARG(StyleList, EnableDelete, void*, void)
{
    bool bEnableDelete(false);
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
    {
        OSL_ENSURE(m_pStyleSheetPool, "No StyleSheetPool");
        const OUString aTemplName(GetSelectedEntry());
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
        const SfxStyleFamily eFam = pItem->GetFamily();
        SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
        if (pItem->GetFilterList().size() > m_nActFilter)
            nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
        if (nFilter == SfxStyleSearchBits::Auto// automatic
            nFilter = m_nAppFilter;
        const SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(
            aTemplName, eFam, m_xTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);

        OSL_ENSURE(pStyle, "Style not found");
        if (pStyle && pStyle->IsUserDefined())
        {
            if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
            {
                bEnableDelete = true;
            }
        }
    }
    m_pParentDialog->EnableDel(bEnableDelete, this);
}

IMPL_LINK_NOARG(StyleList, Clear, void*, void)
{
    if (m_pCurObjShell && m_bModuleHasStylesSpotlightFeature)
    {
        SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
        if (pViewShell)
        {
            pViewShell->GetStylesSpotlightParaColorMap().clear();
            pViewShell->GetStylesSpotlightCharColorMap().clear();
        }
    }
    m_aStyleFamilies.clear();
    for (auto& i : m_pFamilyState)
        i.reset();
    m_pCurObjShell = nullptr;
    for (auto& i : pBoundItems)
        i.reset();
}

IMPL_LINK(StyleList, OnPopupEnd, const OUString&, sCommand, void) { MenuSelect(sCommand); }

void StyleList::ShowMenu(const CommandEvent& rCEvt)
{
    CreateContextMenu();
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    mxMenu->connect_activate(LINK(this, StyleList, OnPopupEnd));
    mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
}

void StyleList::MenuSelect(const OUString& rIdent)
{
    sLastItemIdent = rIdent;
    if (sLastItemIdent.isEmpty())
        return;
    Application::PostUserEvent(LINK(this, StyleList, MenuSelectAsyncHdl)); /***check this****/
}

void StyleList::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
{
    const SfxHintId nId = rHint.GetId();

    switch (nId)
    {
        case SfxHintId::UpdateDone:
        {
            SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
            SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
            if (m_pParentDialog->GetNotifyUpdate()
                && (!m_pParentDialog->IsCheckedItem(u"watercan"_ustr)
                    || (pDocShell && pDocShell->GetStyleSheetPool() != m_pStyleSheetPool)))
            {
                m_pParentDialog->SetNotifyupdate(false);
                Update();
            }
            else if (m_bUpdateFamily)
            {
                UpdateFamily();
                m_aUpdateFamily.Call(*this);
            }

            if (m_pStyleSheetPool)
            {
                OUString aStr = GetSelectedEntry();
                if (!aStr.isEmpty())
                {
                    const SfxStyleFamilyItem* pItem = GetFamilyItem();
                    if (!pItem)
                        break;
                    const SfxStyleFamily eFam = pItem->GetFamily();
                    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aStr, eFam);
                    if (pStyle)
                    {
                        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
                        m_pParentDialog->EnableEdit(bReadWrite, this);
                        m_pParentDialog->EnableHide(
                            bReadWrite && !pStyle->IsUsed() && !pStyle->IsHidden(), this);
                        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
                    }
                    else
                    {
                        m_pParentDialog->EnableEdit(falsethis);
                        m_pParentDialog->EnableHide(falsethis);
                        m_pParentDialog->EnableShow(falsethis);
                    }
                }
            }
            break;
        }

        // Necessary if switching between documents and in both documents
        // the same template is used. Do not immediately call Update_Impl,
        // for the case that one of the documents is an internal InPlaceObject!
        case SfxHintId::DocChanged:
            m_pParentDialog->SetNotifyupdate(true);
            break;
        case SfxHintId::Dying:
        {
            EndListening(*m_pStyleSheetPool);
            m_pStyleSheetPool = nullptr;
            break;
        }
        default:
            break;
    }

    // Do not set timer when the stylesheet pool is in the box, because it is
    // possible that a new one is registered after the timer is up -
    // works bad in UpdateStyles_Impl ()!

    if (!m_bDontUpdate && nId != SfxHintId::Dying
        && (nId == SfxHintId::SfxStyleSheetPool || dynamic_cast<const SfxStyleSheetHint*>(&rHint)
            || nId == SfxHintId::StyleSheetModifiedExtended)) // ie. SfxStyleSheetModifiedHint
    {
        if (!pIdle)
        {
            pIdle.reset(new Idle("SfxCommonTemplate"));
            pIdle->SetPriority(TaskPriority::LOWEST);
            pIdle->SetInvokeHandler(LINK(this, StyleList, TimeOut));
        }
        pIdle->Start();
    }
}

IMPL_LINK_NOARG(StyleList, TimeOut, Timer*, void)
{
    if (!m_bDontUpdate)
    {
        m_bDontUpdate = true;
        if (!m_xTreeBox->get_visible())
            UpdateStyles(StyleFlags::UpdateFamilyList);
        else
        {
            FillTreeBox(GetActualFamily());
            SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
            if (pState)
            {
                m_pParentDialog->SelectStyle(pState->GetStyleName(), false, *this);
                EnableDelete(nullptr);
            }
        }
        m_bDontUpdate = false;
        pIdle.reset();
    }
    else
        pIdle->Start();
}

IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, void)
{
    if (sLastItemIdent == "new")
        NewHdl();
    else if (sLastItemIdent == "edit")
        EditHdl();
    else if (sLastItemIdent == "delete")
        DeleteHdl();
    else if (sLastItemIdent == "hide")
        HideHdl();
    else if (sLastItemIdent == "show")
        ShowHdl();

    mxMenu.reset();
    mxMenuBuilder.reset();
}

// Double-click on a style sheet in the ListBox is applied.
IMPL_LINK(StyleList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
{
    rUnsetDragIcon = false;
    // Allow normal processing. only if bAllowReParentDrop is true
    return !m_bAllowReParentDrop;
}

IMPL_LINK(StyleList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
{
    bool bRet = false;
    const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
    if (m_bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
    {
        DeleteHdl();
        bRet = true;
    }
    return bRet;
}

IMPL_LINK(StyleList, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
{
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
    const OUString aTemplName(pTreeView->get_text(rEntry));
    OUString sQuickHelpText(aTemplName);

    const SfxStyleFamilyItem* pItem = GetFamilyItem();
    if (!pItem)
        return sQuickHelpText;
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
    if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document?
    {
        OUString sUsedBy;
        if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
            sUsedBy = pStyle->GetUsedBy();

        if (!sUsedBy.isEmpty())
        {
            const sal_Int32 nMaxLen = 80;
            if (sUsedBy.getLength() > nMaxLen)
            {
                sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
            }

            OUString aMessage = SfxResId(STR_STYLEUSEDBY);
            aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
            sQuickHelpText = aTemplName + " " + aMessage;
        }
    }

    return sQuickHelpText;
}

IMPL_LINK(StyleList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
{
    vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
    const ::tools::Rectangle& rRect = std::get<1>(aPayload);
    ::tools::Rectangle aRect(
        rRect.TopLeft(),
        Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
    bool bSelected = std::get<2>(aPayload);
    const OUString& rId = std::get<3>(aPayload);

    rRenderContext.Push(vcl::PushFlags::TEXTCOLOR);
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    if (bSelected)
        rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
    else
        rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());

    bool bSuccess = false;

    SfxObjectShell* pShell = SfxObjectShell::Current();
    sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager() : nullptr;

    if (pStyleManager)
    {
        if (const SfxStyleFamilyItem* pItem = GetFamilyItem())
        {
            SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());

            if (pStyleSheet)
            {
                rRenderContext.Push(vcl::PushFlags::ALL);
                // tdf#119919 - show "hidden" styles as disabled to not move children onto root node
                if (pStyleSheet->IsHidden() && m_bHierarchical)
                    rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());

                sal_Int32 nSize = aRect.GetHeight();
                std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
                    pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
                bSuccess
                    = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
                rRenderContext.Pop();
            }
        }
    }

    if (!bSuccess)
        rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);

    rRenderContext.Pop();
}

// Selection of a template during the Watercan-Status
--> --------------------

--> maximum size reached

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

Messung V0.5
C=94 H=97 G=95

¤ Dauer der Verarbeitung: 0.26 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge