Coverage Report

Created: 2025-12-31 10:39

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/StyleList.cxx
Line
Count
Source
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2
/*
3
 * This file is part of the LibreOffice project.
4
 *
5
 * This Source Code Form is subject to the terms of the Mozilla Public
6
 * License, v. 2.0. If a copy of the MPL was not distributed with this
7
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8
 *
9
 * This file incorporates work covered by the following license notice:
10
 *
11
 *   Licensed to the Apache Software Foundation (ASF) under one or more
12
 *   contributor license agreements. See the NOTICE file distributed
13
 *   with this work for additional information regarding copyright
14
 *   ownership. The ASF licenses this file to you under the Apache
15
 *   License, Version 2.0 (the "License"); you may not use this file
16
 *   except in compliance with the License. You may obtain a copy of
17
 *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
18
 */
19
20
#include <memory>
21
#include <unordered_map>
22
23
#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
24
#include <com/sun/star/beans/XPropertySet.hpp>
25
#include <com/sun/star/container/XNameAccess.hpp>
26
#include <utility>
27
#include <vcl/commandevent.hxx>
28
#include <vcl/commandinfoprovider.hxx>
29
#include <vcl/event.hxx>
30
#include <vcl/settings.hxx>
31
#include <vcl/svapp.hxx>
32
#include <vcl/weld/weldutils.hxx>
33
#include <vcl/window.hxx>
34
#include <svl/intitem.hxx>
35
#include <svl/style.hxx>
36
#include <svl/itemset.hxx>
37
#include <comphelper/lok.hxx>
38
#include <comphelper/processfactory.hxx>
39
#include <officecfg/Office/Common.hxx>
40
41
#include <osl/diagnose.h>
42
#include <sfx2/dispatch.hxx>
43
#include <sfx2/bindings.hxx>
44
#include <templdgi.hxx>
45
#include <tplcitem.hxx>
46
#include <sfx2/styfitem.hxx>
47
#include <sfx2/objsh.hxx>
48
#include <sfx2/viewsh.hxx>
49
#include <sfx2/newstyle.hxx>
50
#include <sfx2/tplpitem.hxx>
51
#include <sfx2/sfxresid.hxx>
52
53
#include <sfx2/sfxsids.hrc>
54
#include <sfx2/strings.hrc>
55
#include <sfx2/docfac.hxx>
56
#include <sfx2/module.hxx>
57
#include <helpids.h>
58
#include <sfx2/viewfrm.hxx>
59
60
#include <comphelper/string.hxx>
61
62
#include <sfx2/StyleManager.hxx>
63
#include <sfx2/StylePreviewRenderer.hxx>
64
65
#include <StyleList.hxx>
66
67
#include <vcl/virdev.hxx>
68
#include <basegfx/color/bcolortools.hxx>
69
#include <random>
70
71
using namespace css;
72
using namespace css::beans;
73
using namespace css::frame;
74
using namespace css::uno;
75
76
class TreeViewDropTarget final : public DropTargetHelper
77
{
78
private:
79
    StyleList& m_rParent;
80
81
public:
82
    TreeViewDropTarget(StyleList& rStyleList, weld::TreeView& rTreeView)
83
0
        : DropTargetHelper(rTreeView.get_drop_target())
84
0
        , m_rParent(rStyleList)
85
0
    {
86
0
    }
87
88
    virtual sal_Int8 AcceptDrop(const AcceptDropEvent& rEvt) override
89
0
    {
90
0
        return m_rParent.AcceptDrop(rEvt, *this);
91
0
    }
92
93
    virtual sal_Int8 ExecuteDrop(const ExecuteDropEvent& rEvt) override
94
0
    {
95
0
        return m_rParent.ExecuteDrop(rEvt);
96
0
    }
97
};
98
99
Color ColorHash(std::u16string_view rString)
100
0
{
101
0
    static constexpr auto aSaturationArray = std::to_array<sal_uInt16>({ 90, 75, 60 });
102
0
    static constexpr auto aBrightnessArray = std::to_array<sal_uInt16>({ 100, 80, 60 });
103
0
    static constexpr auto aTintOrShadeArray
104
0
        = std::to_array<sal_Int16>({ 1'500, 3'000, 4'500, 6'500, 7'500 });
105
106
0
    sal_uInt32 nStringHash = rtl_ustr_hashCode_WithLength(rString.data(), rString.length());
107
108
    // Twist the hash number with a RNG twister so we can get very different number even when the string hash
109
    // differs only slightly. For example "Heading 1" and "Heading 2" are very close, so we would get a color
110
    // that is very similar and with number quantization could result in the same color.
111
0
    std::mt19937 twister;
112
0
    twister.seed(nStringHash); // setting the hash for
113
0
    nStringHash = twister();
114
115
0
    double fHue = (nStringHash % 60) * 6;
116
0
    nStringHash = nStringHash / 60;
117
118
0
    double fSaturation = aSaturationArray[nStringHash % aSaturationArray.size()];
119
0
    nStringHash = nStringHash / aSaturationArray.size();
120
121
0
    double fBrightness = aBrightnessArray[nStringHash % aBrightnessArray.size()];
122
0
    nStringHash = nStringHash / aBrightnessArray.size();
123
124
0
    auto aColor = Color::HSBtoRGB(fHue, fSaturation, fBrightness);
125
0
    double fTintOrShade = aTintOrShadeArray[nStringHash % aTintOrShadeArray.size()];
126
0
    aColor.ApplyTintOrShade(fTintOrShade);
127
128
0
    return aColor;
129
0
}
130
131
namespace
132
{
133
// used to disallow the default character style in the styles spotlight character styles color map
134
std::optional<OUString> sDefaultCharStyleUIName;
135
}
136
137
// Constructor
138
139
StyleList::StyleList(weld::Builder* pBuilder, SfxBindings* pBindings,
140
                     SfxCommonTemplateDialog_Impl* Parent, weld::Container* pC,
141
                     const OUString& treeviewname, const OUString& flatviewname)
142
0
    : m_bHierarchical(false)
143
0
    , m_bAllowReParentDrop(false)
144
0
    , m_bNewByExampleDisabled(false)
145
0
    , m_bDontUpdate(false)
146
0
    , m_bTreeDrag(true)
147
0
    , m_bCanEdit(false)
148
0
    , m_bCanHide(true)
149
0
    , m_bCanShow(false)
150
0
    , m_bCanNew(true)
151
0
    , m_bUpdateFamily(false)
152
0
    , m_bCanDel(false)
153
0
    , m_bBindingUpdate(true)
154
0
    , m_pStyleSheetPool(nullptr)
155
0
    , m_nActFilter(0)
156
0
    , m_xFmtLb(pBuilder->weld_tree_view(flatviewname))
157
0
    , m_xTreeBox(pBuilder->weld_tree_view(treeviewname))
158
0
    , m_pCurObjShell(nullptr)
159
0
    , m_nActFamily(0xffff)
160
0
    , m_nAppFilter(SfxStyleSearchBits::Auto)
161
0
    , m_pParentDialog(Parent)
162
0
    , m_pBindings(pBindings)
163
0
    , m_Module(nullptr)
164
0
    , m_nModifier(0)
165
0
    , m_pContainer(pC)
166
0
{
167
0
    m_xFmtLb->set_help_id(HID_TEMPLATE_FMT);
168
169
0
    uno::Reference<frame::XFrame> xFrame
170
0
        = m_pBindings->GetDispatcher()->GetFrame()->GetFrame().GetFrameInterface();
171
0
    m_bModuleHasStylesSpotlightFeature
172
0
        = vcl::CommandInfoProvider::GetModuleIdentifier(xFrame) == "com.sun.star.text.TextDocument";
173
0
}
174
175
// Destructor
176
177
0
StyleList::~StyleList() {}
178
179
// Called in the destructor of Dialog
180
// Cleans up the StyleList individual components while closing the application
181
IMPL_LINK_NOARG(StyleList, Cleanup, void*, void)
182
0
{
183
0
    if (m_pStyleSheetPool)
184
0
        EndListening(*m_pStyleSheetPool);
185
0
    m_pStyleSheetPool = nullptr;
186
0
    m_xTreeView1DropTargetHelper.reset();
187
0
    m_xTreeView2DropTargetHelper.reset();
188
0
    m_xTreeBox.reset();
189
0
    m_xFmtLb.reset();
190
0
    pIdle.reset();
191
0
}
192
193
void StyleList::CreateContextMenu()
194
0
{
195
0
    if (m_bBindingUpdate)
196
0
    {
197
0
        m_pBindings->Invalidate(SID_STYLE_NEW, true);
198
0
        m_pBindings->Update(SID_STYLE_NEW);
199
0
        m_bBindingUpdate = false;
200
0
    }
201
0
    mxMenu.reset();
202
0
    mxMenuBuilder = Application::CreateBuilder(m_pContainer, u"sfx/ui/stylecontextmenu.ui"_ustr);
203
0
    mxMenu = mxMenuBuilder->weld_menu(u"menu"_ustr);
204
0
    mxMenu->set_sensitive(u"edit"_ustr, m_bCanEdit);
205
0
    mxMenu->set_sensitive(u"delete"_ustr, m_bCanDel);
206
0
    mxMenu->set_sensitive(u"new"_ustr, m_bCanNew);
207
0
    mxMenu->set_sensitive(u"hide"_ustr, m_bCanHide);
208
0
    mxMenu->set_sensitive(u"show"_ustr, m_bCanShow);
209
210
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
211
0
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet
212
0
    {
213
0
        mxMenu->set_sensitive(u"edit"_ustr, false);
214
0
        mxMenu->set_sensitive(u"new"_ustr, false);
215
0
    }
216
0
    if (pItem && pItem->GetFamily() == SfxStyleFamily::Pseudo)
217
0
    {
218
0
        const OUString aTemplName(GetSelectedEntry());
219
0
        if (aTemplName == "No List")
220
0
        {
221
0
            mxMenu->set_sensitive(u"edit"_ustr, false);
222
0
            mxMenu->set_sensitive(u"new"_ustr, false);
223
0
            mxMenu->set_sensitive(u"hide"_ustr, false);
224
0
        }
225
0
    }
226
0
}
227
228
IMPL_LINK_NOARG(StyleList, ReadResource, void*, size_t)
229
0
{
230
    // Read global user resource
231
0
    for (auto& i : m_pFamilyState)
232
0
        i.reset();
233
234
0
    SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
235
0
    m_pCurObjShell = pViewFrame->GetObjectShell();
236
0
    m_Module = m_pCurObjShell ? m_pCurObjShell->GetModule() : nullptr;
237
0
    if (m_Module)
238
0
        m_aStyleFamilies = m_Module->CreateStyleFamilies();
239
240
0
    m_nActFilter = 0xffff;
241
242
0
    if (m_pCurObjShell)
243
0
    {
244
0
        m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(m_pCurObjShell));
245
0
        if (0xffff == m_nActFilter)
246
0
        {
247
0
            m_nActFilter = m_pCurObjShell->GetAutoStyleFilterIndex();
248
0
        }
249
0
        if (m_bModuleHasStylesSpotlightFeature)
250
0
            sDefaultCharStyleUIName = getDefaultStyleName(SfxStyleFamily::Char);
251
0
    }
252
0
    size_t nCount = m_aStyleFamilies.size();
253
0
    m_pBindings->ENTERREGISTRATIONS();
254
255
0
    size_t i;
256
0
    for (i = 0; i < nCount; ++i)
257
0
    {
258
0
        sal_uInt16 nSlot = 0;
259
0
        switch (m_aStyleFamilies.at(i).GetFamily())
260
0
        {
261
0
            case SfxStyleFamily::Char:
262
0
                nSlot = SID_STYLE_FAMILY1;
263
0
                break;
264
0
            case SfxStyleFamily::Para:
265
0
                nSlot = SID_STYLE_FAMILY2;
266
0
                break;
267
0
            case SfxStyleFamily::Frame:
268
0
                nSlot = SID_STYLE_FAMILY3;
269
0
                break;
270
0
            case SfxStyleFamily::Page:
271
0
                nSlot = SID_STYLE_FAMILY4;
272
0
                break;
273
0
            case SfxStyleFamily::Pseudo:
274
0
                nSlot = SID_STYLE_FAMILY5;
275
0
                break;
276
0
            case SfxStyleFamily::Table:
277
0
                nSlot = SID_STYLE_FAMILY6;
278
0
                break;
279
0
            default:
280
0
                OSL_FAIL("unknown StyleFamily");
281
0
                break;
282
0
        }
283
0
        pBoundItems[i].reset(new SfxTemplateControllerItem(nSlot, *m_pParentDialog, *m_pBindings));
284
0
    }
285
0
    pBoundItems[i++].reset(
286
0
        new SfxTemplateControllerItem(SID_STYLE_WATERCAN, *m_pParentDialog, *m_pBindings));
287
0
    pBoundItems[i++].reset(
288
0
        new SfxTemplateControllerItem(SID_STYLE_NEW_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
289
0
    pBoundItems[i++].reset(
290
0
        new SfxTemplateControllerItem(SID_STYLE_UPDATE_BY_EXAMPLE, *m_pParentDialog, *m_pBindings));
291
0
    pBoundItems[i++].reset(
292
0
        new SfxTemplateControllerItem(SID_STYLE_NEW, *m_pParentDialog, *m_pBindings));
293
0
    pBoundItems[i++].reset(
294
0
        new SfxTemplateControllerItem(SID_STYLE_DRAGHIERARCHIE, *m_pParentDialog, *m_pBindings));
295
0
    pBoundItems[i++].reset(
296
0
        new SfxTemplateControllerItem(SID_STYLE_EDIT, *m_pParentDialog, *m_pBindings));
297
0
    pBoundItems[i++].reset(
298
0
        new SfxTemplateControllerItem(SID_STYLE_DELETE, *m_pParentDialog, *m_pBindings));
299
0
    pBoundItems[i++].reset(
300
0
        new SfxTemplateControllerItem(SID_STYLE_FAMILY, *m_pParentDialog, *m_pBindings));
301
0
    m_pBindings->LEAVEREGISTRATIONS();
302
303
0
    for (; i < COUNT_BOUND_FUNC; ++i)
304
0
        pBoundItems[i] = nullptr;
305
306
0
    StartListening(*m_pBindings);
307
308
0
    for (i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++)
309
0
        m_pBindings->Update(i);
310
311
0
    return nCount;
312
0
}
313
314
void StyleList::EnableNewByExample(bool newByExampleDisabled)
315
0
{
316
0
    m_bNewByExampleDisabled = newByExampleDisabled;
317
0
}
318
319
void StyleList::FilterSelect(sal_uInt16 nActFilter, bool bsetFilter)
320
0
{
321
0
    m_nActFilter = nActFilter;
322
0
    if (bsetFilter)
323
0
    {
324
0
        SfxObjectShell* const pDocShell = m_aSaveSelection.Call(*this);
325
0
        SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
326
0
        m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
327
0
        if (pOldStyleSheetPool != m_pStyleSheetPool)
328
0
        {
329
0
            if (pOldStyleSheetPool)
330
0
                EndListening(*pOldStyleSheetPool);
331
0
            if (m_pStyleSheetPool)
332
0
                StartListening(*m_pStyleSheetPool);
333
0
        }
334
0
    }
335
0
    UpdateStyles(StyleFlags::UpdateFamilyList);
336
0
}
337
338
IMPL_LINK(StyleList, SetFamily, sal_uInt16, nId, void)
339
0
{
340
0
    if (m_nActFamily != 0xFFFF)
341
0
        m_pParentDialog->CheckItem(OUString::number(m_nActFamily), false);
342
0
    m_nActFamily = nId;
343
0
    if (nId != 0xFFFF)
344
0
    {
345
0
        m_bUpdateFamily = true;
346
0
    }
347
0
}
348
349
void StyleList::InvalidateBindings()
350
0
{
351
0
    m_pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true);
352
0
    m_pBindings->Update(SID_STYLE_NEW_BY_EXAMPLE);
353
0
    m_pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true);
354
0
    m_pBindings->Update(SID_STYLE_UPDATE_BY_EXAMPLE);
355
0
    m_pBindings->Invalidate(SID_STYLE_WATERCAN, true);
356
0
    m_pBindings->Update(SID_STYLE_WATERCAN);
357
0
    m_pBindings->Invalidate(SID_STYLE_NEW, true);
358
0
    m_pBindings->Update(SID_STYLE_NEW);
359
0
    m_pBindings->Invalidate(SID_STYLE_DRAGHIERARCHIE, true);
360
0
    m_pBindings->Update(SID_STYLE_DRAGHIERARCHIE);
361
0
}
362
363
void StyleList::Initialize()
364
0
{
365
0
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
366
0
    m_pBindings->Update(SID_STYLE_FAMILY);
367
368
0
    m_xFmtLb->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
369
0
    m_xFmtLb->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
370
0
    m_xFmtLb->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
371
0
    m_xFmtLb->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
372
0
    m_xFmtLb->connect_command(LINK(this, StyleList, PopupFlatMenuHdl));
373
0
    m_xFmtLb->connect_key_press(LINK(this, StyleList, KeyInputHdl));
374
0
    m_xFmtLb->set_selection_mode(SelectionMode::Multiple);
375
0
    m_xTreeBox->connect_selection_changed(LINK(this, StyleList, FmtSelectHdl));
376
0
    m_xTreeBox->connect_row_activated(LINK(this, StyleList, TreeListApplyHdl));
377
0
    m_xTreeBox->connect_mouse_press(LINK(this, StyleList, MousePressHdl));
378
0
    m_xTreeBox->connect_query_tooltip(LINK(this, StyleList, QueryTooltipHdl));
379
0
    m_xTreeBox->connect_command(LINK(this, StyleList, PopupTreeMenuHdl));
380
0
    m_xTreeBox->connect_key_press(LINK(this, StyleList, KeyInputHdl));
381
0
    m_xTreeBox->connect_drag_begin(LINK(this, StyleList, DragBeginHdl));
382
0
    m_xTreeView1DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xFmtLb));
383
0
    m_xTreeView2DropTargetHelper.reset(new TreeViewDropTarget(*this, *m_xTreeBox));
384
385
0
    m_pParentDialog->connect_stylelist_read_resource(LINK(this, StyleList, ReadResource));
386
0
    m_pParentDialog->connect_stylelist_clear(LINK(this, StyleList, Clear));
387
0
    m_pParentDialog->connect_stylelist_cleanup(LINK(this, StyleList, Cleanup));
388
0
    m_pParentDialog->connect_stylelist_execute_drop(LINK(this, StyleList, ExecuteDrop));
389
0
    m_pParentDialog->connect_stylelist_execute_new_menu(
390
0
        LINK(this, StyleList, NewMenuExecuteAction));
391
0
    m_pParentDialog->connect_stylelist_for_watercan(LINK(this, StyleList, IsSafeForWaterCan));
392
0
    m_pParentDialog->connect_stylelist_has_selected_style(LINK(this, StyleList, HasSelectedStyle));
393
0
    m_pParentDialog->connect_stylelist_update_style_dependents(
394
0
        LINK(this, StyleList, UpdateStyleDependents));
395
0
    m_pParentDialog->connect_stylelist_enable_tree_drag(LINK(this, StyleList, EnableTreeDrag));
396
0
    m_pParentDialog->connect_stylelist_enable_delete(LINK(this, StyleList, EnableDelete));
397
0
    m_pParentDialog->connect_stylelist_set_water_can_state(LINK(this, StyleList, SetWaterCanState));
398
0
    m_pParentDialog->connect_set_family(LINK(this, StyleList, SetFamily));
399
400
0
    int nTreeHeight = m_xFmtLb->get_height_rows(8);
401
0
    m_xFmtLb->set_size_request(-1, nTreeHeight);
402
0
    m_xTreeBox->set_size_request(-1, nTreeHeight);
403
404
0
    m_xFmtLb->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
405
0
    m_xFmtLb->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
406
0
    m_xTreeBox->connect_custom_get_size(LINK(this, StyleList, CustomGetSizeHdl));
407
0
    m_xTreeBox->connect_custom_render(LINK(this, StyleList, CustomRenderHdl));
408
0
    bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
409
0
    m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
410
0
    m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);
411
412
0
    m_xFmtLb->set_visible(!m_bHierarchical);
413
0
    m_xTreeBox->set_visible(m_bHierarchical);
414
0
    Update();
415
0
}
416
417
void StyleList::UpdateFamily()
418
0
{
419
0
    m_bUpdateFamily = false;
420
421
0
    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
422
0
    SfxViewFrame* pViewFrame = pDispat->GetFrame();
423
0
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
424
425
0
    SfxStyleSheetBasePool* pOldStyleSheetPool = m_pStyleSheetPool;
426
0
    m_pStyleSheetPool = pDocShell ? pDocShell->GetStyleSheetPool() : nullptr;
427
0
    if (pOldStyleSheetPool != m_pStyleSheetPool)
428
0
    {
429
0
        if (pOldStyleSheetPool)
430
0
            EndListening(*pOldStyleSheetPool);
431
0
        if (m_pStyleSheetPool)
432
0
            StartListening(*m_pStyleSheetPool);
433
0
    }
434
435
0
    m_bTreeDrag = true;
436
0
    m_bCanNew = m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
437
0
    m_pParentDialog->EnableNew(m_bCanNew, this);
438
0
    m_bTreeDrag = true;
439
0
    if (m_pStyleSheetPool)
440
0
    {
441
0
        if (!m_xTreeBox->get_visible())
442
0
            UpdateStyles(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList);
443
0
        else
444
0
        {
445
0
            UpdateStyles(StyleFlags::UpdateFamily);
446
0
            FillTreeBox(GetActualFamily());
447
0
        }
448
0
    }
449
450
0
    InvalidateBindings();
451
0
}
452
453
bool StyleList::EnableExecute()
454
0
{
455
0
    return m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1;
456
0
}
457
458
void StyleList::connect_LoadFactoryStyleFilter(const Link<SfxObjectShell const*, sal_Int32>& rLink)
459
0
{
460
0
    m_aLoadFactoryStyleFilter = rLink;
461
0
}
462
463
void StyleList::connect_SaveSelection(const Link<StyleList&, SfxObjectShell*> rLink)
464
0
{
465
0
    m_aSaveSelection = rLink;
466
0
}
467
468
/** Drop is enabled as long as it is allowed to create a new style by example, i.e. to
469
    create a style out of the current selection.
470
*/
471
sal_Int8 StyleList::AcceptDrop(const AcceptDropEvent& rEvt, const DropTargetHelper& rHelper)
472
0
{
473
0
    if (rHelper.IsDropFormatSupported(SotClipboardFormatId::OBJECTDESCRIPTOR))
474
0
    {
475
        // special case: page styles are allowed to create new styles by example
476
        // but not allowed to be created by drag and drop
477
0
        if (GetActualFamily() == SfxStyleFamily::Page || m_bNewByExampleDisabled)
478
0
            return DND_ACTION_NONE;
479
0
        else
480
0
            return DND_ACTION_COPY;
481
0
    }
482
    // to enable the autoscroll when we're close to the edges
483
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
484
0
    pTreeView->get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
485
0
    return DND_ACTION_MOVE;
486
0
}
487
488
// handles drop of content in treeview when creating a new style
489
IMPL_LINK(StyleList, ExecuteDrop, const ExecuteDropEvent&, rEvt, sal_Int8)
490
0
{
491
0
    SfxObjectShell* pDocShell = m_pCurObjShell;
492
0
    if (pDocShell)
493
0
    {
494
0
        TransferableDataHelper aHelper(rEvt.maDropEvent.Transferable);
495
0
        sal_uInt32 nFormatCount = aHelper.GetFormatCount();
496
497
0
        sal_Int8 nRet = DND_ACTION_NONE;
498
499
0
        bool bFormatFound = false;
500
501
0
        for (sal_uInt32 i = 0; i < nFormatCount; ++i)
502
0
        {
503
0
            SotClipboardFormatId nId = aHelper.GetFormat(i);
504
0
            TransferableObjectDescriptor aDesc;
505
506
0
            if (aHelper.GetTransferableObjectDescriptor(nId, aDesc))
507
0
            {
508
0
                if (aDesc.maClassName == pDocShell->GetFactory().GetClassId())
509
0
                {
510
0
                    Application::PostUserEvent(
511
0
                        LINK(m_pParentDialog, SfxCommonTemplateDialog_Impl, OnAsyncExecuteDrop),
512
0
                        this);
513
514
0
                    bFormatFound = true;
515
0
                    nRet = rEvt.mnAction;
516
0
                    break;
517
0
                }
518
0
            }
519
0
        }
520
521
0
        if (bFormatFound)
522
0
            return nRet;
523
0
    }
524
525
0
    if (!m_xTreeBox->get_visible())
526
0
        return DND_ACTION_NONE;
527
528
0
    if (!m_bAllowReParentDrop)
529
0
        return DND_ACTION_NONE;
530
531
    // otherwise if we're dragging with the treeview to set a new parent of the dragged style
532
0
    weld::TreeView* pSource = m_xTreeBox->get_drag_source();
533
    // only dragging within the same widget allowed
534
0
    if (!pSource || pSource != m_xTreeBox.get())
535
0
        return DND_ACTION_NONE;
536
537
0
    std::unique_ptr<weld::TreeIter> xSource = m_xTreeBox->get_selected();
538
0
    if (!xSource)
539
0
        return DND_ACTION_NONE;
540
541
0
    std::unique_ptr<weld::TreeIter> xTarget(m_xTreeBox->make_iterator());
542
0
    if (!m_xTreeBox->get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true))
543
0
    {
544
        // if nothing under the mouse, use the last row
545
0
        int nChildren = m_xTreeBox->n_children();
546
0
        if (!nChildren)
547
0
            return DND_ACTION_NONE;
548
0
        if (!m_xTreeBox->get_iter_first(*xTarget)
549
0
            || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
550
0
            return DND_ACTION_NONE;
551
0
        while (m_xTreeBox->get_row_expanded(*xTarget))
552
0
        {
553
0
            nChildren = m_xTreeBox->iter_n_children(*xTarget);
554
0
            if (!m_xTreeBox->iter_children(*xTarget)
555
0
                || !m_xTreeBox->iter_nth_sibling(*xTarget, nChildren - 1))
556
0
                return DND_ACTION_NONE;
557
0
        }
558
0
    }
559
0
    OUString aTargetStyle = m_xTreeBox->get_text(*xTarget);
560
0
    DropHdl(m_xTreeBox->get_text(*xSource), aTargetStyle);
561
0
    m_xTreeBox->unset_drag_dest_row();
562
0
    FillTreeBox(GetActualFamily());
563
0
    m_pParentDialog->SelectStyle(aTargetStyle, false, *this);
564
0
    return DND_ACTION_NONE;
565
0
}
566
567
IMPL_LINK_NOARG(StyleList, NewMenuExecuteAction, void*, void)
568
0
{
569
0
    if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
570
0
        return;
571
572
0
    const SfxStyleFamily eFam = GetFamilyItem()->GetFamily();
573
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
574
0
    SfxStyleSearchBits nFilter(SfxStyleSearchBits::Auto);
575
0
    if (pItem && m_nActFilter != 0xffff)
576
0
        nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
577
0
    if (nFilter == SfxStyleSearchBits::Auto) // automatic
578
0
        nFilter = m_nAppFilter;
579
580
    // why? : FloatingWindow must not be parent of a modal dialog
581
0
    SfxNewStyleDlg aDlg(m_pContainer, *m_pStyleSheetPool, eFam);
582
0
    auto nResult = aDlg.run();
583
0
    if (nResult == RET_OK)
584
0
    {
585
0
        const OUString aTemplName(aDlg.GetName());
586
0
        m_pParentDialog->Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, aTemplName, u""_ustr,
587
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
588
0
                                      nFilter);
589
0
        UpdateFamily();
590
0
        m_aUpdateFamily.Call(*this);
591
0
    }
592
0
}
593
594
void StyleList::DropHdl(const OUString& rStyle, const OUString& rParent)
595
0
{
596
0
    m_bDontUpdate = true;
597
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
598
0
    const SfxStyleFamily eFam = pItem->GetFamily();
599
0
    if (auto pStyle = m_pStyleSheetPool->Find(rStyle, eFam))
600
0
        pStyle->SetParent(rParent);
601
0
    m_bDontUpdate = false;
602
0
}
603
604
void StyleList::PrepareMenu(const Point& rPos)
605
0
{
606
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
607
0
    std::unique_ptr<weld::TreeIter> xIter(pTreeView->make_iterator());
608
0
    if (pTreeView->get_dest_row_at_pos(rPos, xIter.get(), false) && !pTreeView->is_selected(*xIter))
609
0
    {
610
0
        pTreeView->unselect_all();
611
0
        pTreeView->set_cursor(*xIter);
612
0
        pTreeView->select(*xIter);
613
0
    }
614
0
    FmtSelectHdl(*pTreeView);
615
0
}
616
617
/** Internal structure for the establishment of the hierarchical view */
618
namespace
619
{
620
class StyleTree_Impl;
621
}
622
623
typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl;
624
625
namespace
626
{
627
class StyleTree_Impl
628
{
629
private:
630
    OUString aName;
631
    OUString aParent;
632
    sal_Int32 nSpotlightId;
633
    StyleTreeArr_Impl pChildren;
634
635
public:
636
0
    bool HasParent() const { return !aParent.isEmpty(); }
637
638
    StyleTree_Impl(OUString _aName, OUString _aParent, sal_Int32 _nSpotlightId)
639
0
        : aName(std::move(_aName))
640
0
        , aParent(std::move(_aParent))
641
0
        , nSpotlightId(_nSpotlightId)
642
0
        , pChildren(0)
643
0
    {
644
0
    }
645
646
0
    const OUString& getName() const { return aName; }
647
0
    const OUString& getParent() const { return aParent; }
648
0
    sal_Int32 getSpotlightId() const { return nSpotlightId; }
649
0
    StyleTreeArr_Impl& getChildren() { return pChildren; }
650
};
651
}
652
653
static void MakeTree_Impl(StyleTreeArr_Impl& rArr, const OUString& aUIName)
654
0
{
655
0
    const comphelper::string::NaturalStringSorter aSorter(
656
0
        ::comphelper::getProcessComponentContext(),
657
0
        Application::GetSettings().GetLanguageTag().getLocale());
658
659
0
    std::unordered_map<OUString, StyleTree_Impl*> styleFinder;
660
0
    styleFinder.reserve(rArr.size());
661
0
    for (const auto& pEntry : rArr)
662
0
    {
663
0
        styleFinder.emplace(pEntry->getName(), pEntry.get());
664
0
    }
665
666
    // Arrange all under their Parents
667
0
    for (auto& pEntry : rArr)
668
0
    {
669
0
        if (!pEntry->HasParent())
670
0
            continue;
671
0
        auto it = styleFinder.find(pEntry->getParent());
672
0
        if (it != styleFinder.end())
673
0
        {
674
0
            StyleTree_Impl* pCmp = it->second;
675
            // Insert child entries sorted
676
0
            auto iPos = std::lower_bound(
677
0
                pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry,
678
0
                [&aSorter](std::unique_ptr<StyleTree_Impl> const& pEntry1,
679
0
                           std::unique_ptr<StyleTree_Impl> const& pEntry2) {
680
0
                    return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
681
0
                });
682
0
            pCmp->getChildren().insert(iPos, std::move(pEntry));
683
0
        }
684
0
    }
685
686
    // Only keep tree roots in rArr, child elements can be accessed through the hierarchy
687
0
    std::erase_if(rArr, [](std::unique_ptr<StyleTree_Impl> const& pEntry) { return !pEntry; });
688
689
    // tdf#91106 sort top level styles
690
    // Paradoxically, with a list and non-Latin style names,
691
    // sorting twice is faster than sorting once.
692
    // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
693
    // Then the second sort needs to call its (much more expensive) comparator less often.
694
0
    std::sort(rArr.begin(), rArr.end(),
695
0
              [](std::unique_ptr<StyleTree_Impl> const& pEntry1,
696
0
                 std::unique_ptr<StyleTree_Impl> const& pEntry2) {
697
0
                  return pEntry1->getName() < pEntry2->getName();
698
0
              });
699
0
    std::sort(rArr.begin(), rArr.end(),
700
0
              [&aSorter, &aUIName](std::unique_ptr<StyleTree_Impl> const& pEntry1,
701
0
                                   std::unique_ptr<StyleTree_Impl> const& pEntry2) {
702
0
                  if (pEntry2->getName() == aUIName)
703
0
                      return false;
704
0
                  if (pEntry1->getName() == aUIName)
705
0
                      return true; // default always first
706
0
                  return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0;
707
0
              });
708
0
}
709
710
static bool IsExpanded_Impl(const std::vector<OUString>& rEntries, std::u16string_view rStr)
711
0
{
712
0
    for (const auto& rEntry : rEntries)
713
0
    {
714
0
        if (rEntry == rStr)
715
0
            return true;
716
0
    }
717
0
    return false;
718
0
}
719
720
static void lcl_Update(weld::TreeView& rTreeView, const weld::TreeIter& rIter,
721
                       const StyleTree_Impl& rEntry, SfxStyleFamily eFam, SfxViewShell* pViewSh)
722
0
{
723
0
    const OUString& rName = rEntry.getName();
724
725
0
    Color aColor = ColorHash(rName);
726
727
    // For kit keep the id used for spotlight/number-image for a style stable
728
    // regardless of the selection mode of the style panel, so multiple views
729
    // on a document all share the same id for a style.
730
0
    sal_Int32 nSpotlightId;
731
0
    if (comphelper::LibreOfficeKit::isActive())
732
0
        nSpotlightId = rEntry.getSpotlightId();
733
0
    else
734
0
    {
735
0
        StylesSpotlightColorMap& rColorMap = (eFam == SfxStyleFamily::Para)
736
0
                                                 ? pViewSh->GetStylesSpotlightParaColorMap()
737
0
                                                 : pViewSh->GetStylesSpotlightCharColorMap();
738
0
        nSpotlightId = rColorMap.size();
739
0
        rColorMap[rName] = std::pair(aColor, nSpotlightId);
740
0
    }
741
742
0
    if (eFam == SfxStyleFamily::Char)
743
0
    {
744
        // don't show a color or number for default character style 'No Character Style' entry
745
0
        if (rName == sDefaultCharStyleUIName.value() /*"No Character Style"*/)
746
0
        {
747
0
            rTreeView.set_id(rIter, rName);
748
0
            rTreeView.set_text(rIter, rName);
749
0
            return;
750
0
        }
751
0
    }
752
753
    // draw the color rectangle and number image
754
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
755
0
    Size aImageSize = rStyleSettings.GetListBoxPreviewDefaultPixelSize();
756
0
    ScopedVclPtrInstance<VirtualDevice> xDevice;
757
0
    xDevice->SetOutputSize(aImageSize);
758
0
    xDevice->SetFillColor(aColor);
759
0
    const tools::Rectangle aRect(Point(0, 0), aImageSize);
760
0
    xDevice->DrawRect(aRect);
761
    // In kit mode, unused styles are -1, so we can just skip the number image for those
762
0
    if (nSpotlightId != -1)
763
0
    {
764
0
        xDevice->SetTextColor(COL_BLACK);
765
0
        xDevice->DrawText(aRect, OUString::number(nSpotlightId),
766
0
                          DrawTextFlags::Center | DrawTextFlags::VCenter);
767
0
    }
768
769
0
    rTreeView.set_id(rIter, rName);
770
0
    rTreeView.set_text(rIter, rName);
771
0
    rTreeView.set_image(rIter, *xDevice, 0);
772
0
}
773
774
static void FillBox_Impl(weld::TreeView& rBox, StyleTreeArr_Impl& rTreeArray,
775
                         SfxStyleFamily eStyleFamily, const weld::TreeIter* pParent,
776
                         bool blcl_insert, SfxViewShell* pViewShell,
777
                         SfxStyleSheetBasePool* pStyleSheetPool)
778
0
{
779
0
    if (rTreeArray.empty())
780
0
        return;
781
0
    rBox.bulk_insert_for_each(rTreeArray.size(),
782
0
                              [&rTreeArray, blcl_insert, pStyleSheetPool, eStyleFamily, &rBox,
783
0
                               pViewShell](weld::TreeIter& rIter, int i) {
784
0
                                  StyleTree_Impl* pChildEntry = rTreeArray[i].get();
785
0
                                  const OUString& rChildName = pChildEntry->getName();
786
0
                                  if (blcl_insert)
787
0
                                  {
788
0
                                      const SfxStyleSheetBase* pStyle = nullptr;
789
0
                                      if (pStyleSheetPool)
790
0
                                          pStyle = pStyleSheetPool->Find(rChildName, eStyleFamily);
791
0
                                      if (pStyle && pStyle->IsUsed())
792
0
                                          lcl_Update(rBox, rIter, *pChildEntry, eStyleFamily,
793
0
                                                     pViewShell);
794
0
                                      else
795
0
                                      {
796
0
                                          rBox.set_id(rIter, rChildName);
797
0
                                          rBox.set_text(rIter, rChildName);
798
0
                                      }
799
0
                                  }
800
0
                                  else
801
0
                                  {
802
0
                                      rBox.set_id(rIter, rChildName);
803
0
                                      rBox.set_text(rIter, rChildName);
804
0
                                  }
805
0
                              },
806
0
                              pParent, nullptr, /*bGoingToSetText*/ true);
807
808
0
    std::unique_ptr<weld::TreeIter> xChildParentIter = rBox.make_iterator(pParent);
809
0
    if (!pParent)
810
0
        (void)rBox.get_iter_first(*xChildParentIter);
811
0
    else
812
0
        (void)rBox.iter_children(*xChildParentIter);
813
0
    for (size_t i = 0; i < rTreeArray.size(); ++i)
814
0
    {
815
0
        FillBox_Impl(rBox, rTreeArray[i]->getChildren(), eStyleFamily, xChildParentIter.get(),
816
0
                     blcl_insert, pViewShell, pStyleSheetPool);
817
0
        (void)rBox.iter_next_sibling(*xChildParentIter);
818
0
    }
819
0
}
820
821
namespace SfxTemplate
822
{
823
// converts from SFX_STYLE_FAMILY Ids to 1-6
824
static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily)
825
0
{
826
0
    switch (nFamily)
827
0
    {
828
0
        case SfxStyleFamily::Char:
829
0
            return 1;
830
0
        case SfxStyleFamily::Para:
831
0
            return 2;
832
0
        case SfxStyleFamily::Frame:
833
0
            return 3;
834
0
        case SfxStyleFamily::Page:
835
0
            return 4;
836
0
        case SfxStyleFamily::Pseudo:
837
0
            return 5;
838
0
        case SfxStyleFamily::Table:
839
0
            return 6;
840
0
        default:
841
0
            return 0xffff;
842
0
    }
843
0
}
844
// converts from 1-6 to SFX_STYLE_FAMILY Ids
845
static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId)
846
0
{
847
0
    switch (nId)
848
0
    {
849
0
        case 1:
850
0
            return SfxStyleFamily::Char;
851
0
        case 2:
852
0
            return SfxStyleFamily::Para;
853
0
        case 3:
854
0
            return SfxStyleFamily::Frame;
855
0
        case 4:
856
0
            return SfxStyleFamily::Page;
857
0
        case 5:
858
0
            return SfxStyleFamily::Pseudo;
859
0
        case 6:
860
0
            return SfxStyleFamily::Table;
861
0
        default:
862
0
            return SfxStyleFamily::All;
863
0
    }
864
0
}
865
}
866
867
sal_uInt16 StyleList::StyleNrToInfoOffset(sal_uInt16 nId)
868
0
{
869
0
    const SfxStyleFamilyItem& rItem = m_aStyleFamilies.at(nId);
870
0
    return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()) - 1;
871
0
}
872
873
// Helper function: Access to the current family item
874
const SfxStyleFamilyItem* StyleList::GetFamilyItem() const
875
0
{
876
0
    const size_t nCount = m_aStyleFamilies.size();
877
0
    for (size_t i = 0; i < nCount; ++i)
878
0
    {
879
0
        const SfxStyleFamilyItem& rItem = m_aStyleFamilies.at(i);
880
0
        sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily());
881
0
        if (nId == m_nActFamily)
882
0
            return &rItem;
883
0
    }
884
0
    return nullptr;
885
0
}
886
887
void StyleList::GetSelectedStyle() const
888
0
{
889
0
    const OUString aTemplName(GetSelectedEntry());
890
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
891
0
    m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
892
0
}
893
894
// Used to get the current selected entry in visible treeview
895
OUString StyleList::GetSelectedEntry() const
896
0
{
897
0
    OUString aRet;
898
0
    if (m_xTreeBox->get_visible())
899
0
        aRet = m_xTreeBox->get_selected_text();
900
0
    else
901
0
        aRet = m_xFmtLb->get_selected_text();
902
0
    return aRet;
903
0
}
904
905
/**
906
 * Is it safe to show the water-can / fill icon. If we've a
907
 * hierarchical widget - we have only single select, otherwise
908
 * we need to check if we have a multi-selection. We either have
909
 * a m_xTreeBox showing or an m_xFmtLb (which we hide when not shown)
910
 */
911
IMPL_LINK_NOARG(StyleList, IsSafeForWaterCan, void*, bool)
912
0
{
913
0
    if (m_xTreeBox->get_visible())
914
0
        return m_xTreeBox->get_selected_index() != -1;
915
0
    else
916
0
        return m_xFmtLb->count_selected_rows() == 1;
917
0
}
918
919
IMPL_LINK(StyleList, SetWaterCanState, const SfxBoolItem*, pItem, void)
920
0
{
921
0
    size_t nCount = m_aStyleFamilies.size();
922
0
    m_pBindings->EnterRegistrations();
923
0
    for (size_t n = 0; n < nCount; n++)
924
0
    {
925
0
        SfxControllerItem* pCItem = pBoundItems[n].get();
926
0
        bool bChecked = pItem && pItem->GetValue();
927
0
        if (pCItem->IsBound() == bChecked)
928
0
        {
929
0
            if (!bChecked)
930
0
                pCItem->ReBind();
931
0
            else
932
0
                pCItem->UnBind();
933
0
        }
934
0
    }
935
0
    m_pBindings->LeaveRegistrations();
936
0
}
937
938
void StyleList::FamilySelect(sal_uInt16 nEntry, bool bRefresh)
939
0
{
940
0
    if (bRefresh)
941
0
    {
942
0
        bool bCustomPreview = officecfg::Office::Common::StylesAndFormatting::Preview::get();
943
0
        m_xFmtLb->clear();
944
0
        m_xFmtLb->set_column_custom_renderer(1, bCustomPreview);
945
0
        m_xTreeBox->clear();
946
0
        m_xTreeBox->set_column_custom_renderer(1, bCustomPreview);
947
0
    }
948
0
    m_nActFamily = nEntry;
949
0
    SfxDispatcher* pDispat = m_pBindings->GetDispatcher_Impl();
950
0
    SfxUInt16Item const aItem(SID_STYLE_FAMILY,
951
0
                              static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry)));
952
0
    pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem });
953
0
    m_pBindings->Invalidate(SID_STYLE_FAMILY);
954
0
    m_pBindings->Update(SID_STYLE_FAMILY);
955
0
    UpdateFamily();
956
0
    m_aUpdateFamily.Call(*this);
957
0
}
958
959
// It selects the style in treeview
960
// bIsCallBack is true for the selected style. For eg. if "Addressee" is selected in
961
// styles, bIsCallBack will be true for it.
962
void StyleList::SelectStyle(const OUString& rStr, bool bIsCallback)
963
0
{
964
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
965
0
    if (!pItem)
966
0
        return;
967
0
    const SfxStyleFamily eFam = pItem->GetFamily();
968
0
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(rStr, eFam);
969
0
    if (pStyle)
970
0
    {
971
0
        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
972
0
        m_pParentDialog->EnableEdit(bReadWrite, this);
973
0
        m_pParentDialog->EnableHide(bReadWrite && !pStyle->IsHidden() && !pStyle->IsUsed(), this);
974
0
        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
975
0
    }
976
0
    else
977
0
    {
978
0
        m_pParentDialog->EnableEdit(false, this);
979
0
        m_pParentDialog->EnableHide(false, this);
980
0
        m_pParentDialog->EnableShow(false, this);
981
0
    }
982
983
0
    if (bIsCallback)
984
0
        return;
985
986
0
    if (m_xTreeBox->get_visible())
987
0
    {
988
0
        if (!rStr.isEmpty())
989
0
        {
990
0
            std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
991
0
            bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
992
0
            while (bEntry)
993
0
            {
994
0
                if (m_xTreeBox->get_text(*xEntry) == rStr)
995
0
                {
996
0
                    m_xTreeBox->scroll_to_row(*xEntry);
997
0
                    m_xTreeBox->select(*xEntry);
998
0
                    break;
999
0
                }
1000
0
                bEntry = m_xTreeBox->iter_next(*xEntry);
1001
0
            }
1002
0
        }
1003
0
        else if (eFam == SfxStyleFamily::Pseudo)
1004
0
        {
1005
0
            std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
1006
0
            if (m_xTreeBox->get_iter_first(*xEntry))
1007
0
            {
1008
0
                m_xTreeBox->scroll_to_row(*xEntry);
1009
0
                m_xTreeBox->select(*xEntry);
1010
0
            }
1011
0
        }
1012
0
        else
1013
0
            m_xTreeBox->unselect_all();
1014
0
    }
1015
0
    else
1016
0
    {
1017
0
        bool bSelect = !rStr.isEmpty();
1018
0
        if (bSelect)
1019
0
        {
1020
0
            std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
1021
0
            bool bEntry = m_xFmtLb->get_iter_first(*xEntry);
1022
0
            while (bEntry && m_xFmtLb->get_text(*xEntry) != rStr)
1023
0
                bEntry = m_xFmtLb->iter_next(*xEntry);
1024
0
            if (!bEntry)
1025
0
                bSelect = false;
1026
0
            else
1027
0
            {
1028
0
                if (!m_xFmtLb->is_selected(*xEntry))
1029
0
                {
1030
0
                    m_xFmtLb->unselect_all();
1031
0
                    m_xFmtLb->scroll_to_row(*xEntry);
1032
0
                    m_xFmtLb->select(*xEntry);
1033
0
                }
1034
0
            }
1035
0
        }
1036
1037
0
        if (!bSelect)
1038
0
        {
1039
0
            m_xFmtLb->unselect_all();
1040
0
            m_pParentDialog->EnableEdit(false, this);
1041
0
            m_pParentDialog->EnableHide(false, this);
1042
0
            m_pParentDialog->EnableShow(false, this);
1043
0
        }
1044
0
    }
1045
0
}
1046
1047
static void MakeExpanded_Impl(const weld::TreeView& rBox, std::vector<OUString>& rEntries)
1048
0
{
1049
0
    std::unique_ptr<weld::TreeIter> xEntry = rBox.make_iterator();
1050
0
    if (rBox.get_iter_first(*xEntry))
1051
0
    {
1052
0
        do
1053
0
        {
1054
0
            if (rBox.get_row_expanded(*xEntry))
1055
0
                rEntries.push_back(rBox.get_text(*xEntry));
1056
0
        } while (rBox.iter_next(*xEntry));
1057
0
    }
1058
0
}
1059
1060
IMPL_LINK(StyleList, EnableTreeDrag, bool, m_bEnable, void)
1061
0
{
1062
0
    if (m_pStyleSheetPool)
1063
0
    {
1064
0
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
1065
0
        SfxStyleSheetBase* pStyle = pItem ? m_pStyleSheetPool->First(pItem->GetFamily()) : nullptr;
1066
0
        m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bEnable;
1067
0
    }
1068
0
    m_bTreeDrag = m_bEnable;
1069
0
}
1070
1071
// Fill the treeview
1072
1073
void StyleList::FillTreeBox(SfxStyleFamily eFam)
1074
0
{
1075
0
    assert(m_xTreeBox && "FillTreeBox() without treebox");
1076
0
    if (!m_pStyleSheetPool || m_nActFamily == 0xffff)
1077
0
        return;
1078
1079
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1080
0
    if (!pItem)
1081
0
        return;
1082
1083
0
    StyleTreeArr_Impl aArr;
1084
0
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, SfxStyleSearchBits::All);
1085
1086
0
    m_bAllowReParentDrop = pStyle && pStyle->HasParentSupport() && m_bTreeDrag;
1087
1088
0
    while (pStyle)
1089
0
    {
1090
0
        if (pStyle->IsHidden()
1091
0
            && (pStyle->GetFamily() == SfxStyleFamily::Page
1092
0
                || pStyle->GetFamily() == SfxStyleFamily::Pseudo
1093
0
                || pStyle->GetFamily() == SfxStyleFamily::Table))
1094
0
            ;
1095
0
        else
1096
0
        {
1097
0
            StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent(),
1098
0
                                                      pStyle->GetSpotlightId());
1099
0
            aArr.emplace_back(pNew);
1100
0
        }
1101
0
        pStyle = m_pStyleSheetPool->Next();
1102
0
    }
1103
0
    OUString aUIName = getDefaultStyleName(eFam);
1104
0
    MakeTree_Impl(aArr, aUIName);
1105
0
    std::vector<OUString> aEntries;
1106
0
    MakeExpanded_Impl(*m_xTreeBox, aEntries);
1107
0
    m_xTreeBox->freeze();
1108
0
    m_xTreeBox->clear();
1109
0
    const sal_uInt16 nCount = aArr.size();
1110
1111
0
    SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1112
0
    StylesSpotlightColorMap* pSpotlightColorMap = nullptr;
1113
0
    bool bOrigMapHasEntries = false;
1114
0
    if (pViewShell && m_bModuleHasStylesSpotlightFeature)
1115
0
    {
1116
0
        if (eFam == SfxStyleFamily::Para)
1117
0
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightParaColorMap();
1118
0
        else if (eFam == SfxStyleFamily::Char)
1119
0
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightCharColorMap();
1120
0
    }
1121
1122
0
    if (pSpotlightColorMap && !pSpotlightColorMap->empty())
1123
0
    {
1124
0
        bOrigMapHasEntries = true;
1125
0
        pSpotlightColorMap->clear();
1126
0
    }
1127
1128
0
    bool blcl_insert = pViewShell && m_bModuleHasStylesSpotlightFeature
1129
0
                       && ((eFam == SfxStyleFamily::Para && m_bSpotlightParaStyles)
1130
0
                           || (eFam == SfxStyleFamily::Char && m_bSpotlightCharStyles));
1131
1132
0
    FillBox_Impl(*m_xTreeBox, aArr, eFam, nullptr, blcl_insert, pViewShell, m_pStyleSheetPool);
1133
0
    for (sal_uInt16 i = 0; i < nCount; ++i)
1134
0
        aArr[i].reset();
1135
1136
0
    m_xTreeBox->columns_autosize();
1137
1138
0
    m_pParentDialog->EnableItem(u"watercan"_ustr, false);
1139
1140
0
    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1141
1142
0
    m_xTreeBox->thaw();
1143
1144
    // make view update
1145
0
    if (pViewShell && pSpotlightColorMap && (!pSpotlightColorMap->empty() || bOrigMapHasEntries))
1146
0
        static_cast<SfxListener*>(pViewShell)
1147
0
            ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesSpotlightModified));
1148
1149
0
    std::unique_ptr<weld::TreeIter> xEntry = m_xTreeBox->make_iterator();
1150
0
    bool bEntry = m_xTreeBox->get_iter_first(*xEntry);
1151
0
    if (bEntry && nCount)
1152
0
        m_xTreeBox->expand_row(*xEntry);
1153
1154
0
    while (bEntry)
1155
0
    {
1156
0
        if (IsExpanded_Impl(aEntries, m_xTreeBox->get_text(*xEntry)))
1157
0
            m_xTreeBox->expand_row(*xEntry);
1158
0
        bEntry = m_xTreeBox->iter_next(*xEntry);
1159
0
    }
1160
1161
0
    OUString aStyle;
1162
0
    if (pState) // Select current entry
1163
0
        aStyle = pState->GetStyleName();
1164
0
    m_pParentDialog->SelectStyle(aStyle, false, *this);
1165
0
    EnableDelete(nullptr);
1166
0
}
1167
1168
static OUString lcl_GetStyleFamilyName(SfxStyleFamily nFamily)
1169
0
{
1170
0
    if (nFamily == SfxStyleFamily::Char)
1171
0
        return u"CharacterStyles"_ustr;
1172
0
    if (nFamily == SfxStyleFamily::Para)
1173
0
        return u"ParagraphStyles"_ustr;
1174
0
    if (nFamily == SfxStyleFamily::Page)
1175
0
        return u"PageStyles"_ustr;
1176
0
    if (nFamily == SfxStyleFamily::Table)
1177
0
        return u"TableStyles"_ustr;
1178
0
    if (nFamily == SfxStyleFamily::Pseudo)
1179
0
        return u"NumberingStyles"_ustr;
1180
0
    return OUString();
1181
0
}
1182
1183
OUString StyleList::getDefaultStyleName(const SfxStyleFamily eFam)
1184
0
{
1185
0
    OUString sDefaultStyle;
1186
0
    OUString aFamilyName = lcl_GetStyleFamilyName(eFam);
1187
0
    if (aFamilyName == "TableStyles")
1188
0
        sDefaultStyle = "Default Style";
1189
0
    else if (aFamilyName == "NumberingStyles")
1190
0
        sDefaultStyle = "No List";
1191
0
    else
1192
0
        sDefaultStyle = "Standard";
1193
0
    uno::Reference<style::XStyleFamiliesSupplier> xModel(m_pCurObjShell->GetModel(),
1194
0
                                                         uno::UNO_QUERY);
1195
0
    OUString aUIName;
1196
0
    try
1197
0
    {
1198
0
        uno::Reference<container::XNameAccess> xStyles;
1199
0
        uno::Reference<container::XNameAccess> xCont = xModel->getStyleFamilies();
1200
0
        xCont->getByName(aFamilyName) >>= xStyles;
1201
0
        uno::Reference<beans::XPropertySet> xInfo;
1202
0
        xStyles->getByName(sDefaultStyle) >>= xInfo;
1203
0
        xInfo->getPropertyValue(u"DisplayName"_ustr) >>= aUIName;
1204
0
    }
1205
0
    catch (const uno::Exception&)
1206
0
    {
1207
0
    }
1208
0
    return aUIName;
1209
0
}
1210
1211
SfxStyleFamily StyleList::GetActualFamily() const
1212
0
{
1213
0
    const SfxStyleFamilyItem* pFamilyItem = GetFamilyItem();
1214
0
    if (!pFamilyItem || m_nActFamily == 0xffff)
1215
0
        return SfxStyleFamily::Para;
1216
0
    else
1217
0
        return pFamilyItem->GetFamily();
1218
0
}
1219
1220
IMPL_LINK_NOARG(StyleList, HasSelectedStyle, void*, bool)
1221
0
{
1222
0
    return m_xTreeBox->get_visible() ? m_xTreeBox->get_selected_index() != -1
1223
0
                                     : m_xFmtLb->count_selected_rows() != 0;
1224
0
}
1225
1226
IMPL_LINK_NOARG(StyleList, UpdateStyleDependents, void*, void)
1227
0
{
1228
    // Trigger Help PI. Only when the watercan is on
1229
0
    if (m_nActFamily != 0xffff && m_pParentDialog->IsCheckedItem(u"watercan"_ustr) &&
1230
        // only if that region is allowed
1231
0
        nullptr != m_pFamilyState[m_nActFamily - 1] && IsSafeForWaterCan(nullptr))
1232
0
    {
1233
0
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, u""_ustr, u""_ustr, 0, *this);
1234
0
        m_pParentDialog->Execute_Impl(SID_STYLE_WATERCAN, GetSelectedEntry(), u""_ustr,
1235
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1236
0
    }
1237
0
}
1238
1239
// Comes into action when the current style is changed
1240
void StyleList::UpdateStyles(StyleFlags nFlags)
1241
0
{
1242
0
    OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do");
1243
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1244
0
    if (!pItem)
1245
0
    {
1246
        // Is the case for the template catalog
1247
0
        const size_t nFamilyCount = m_aStyleFamilies.size();
1248
0
        size_t n;
1249
0
        for (n = 0; n < nFamilyCount; n++)
1250
0
            if (m_pFamilyState[StyleNrToInfoOffset(n)])
1251
0
                break;
1252
0
        if (n == nFamilyCount)
1253
            // It happens sometimes, God knows why
1254
0
            return;
1255
0
        m_nAppFilter = m_pFamilyState[StyleNrToInfoOffset(n)]->GetValue();
1256
0
        m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1257
0
        pItem = GetFamilyItem();
1258
0
    }
1259
1260
0
    const SfxStyleFamily eFam = pItem->GetFamily();
1261
1262
0
    SfxStyleSearchBits nFilter(m_nActFilter < pItem->GetFilterList().size()
1263
0
                                   ? pItem->GetFilterList()[m_nActFilter].nFlags
1264
0
                                   : SfxStyleSearchBits::Auto);
1265
0
    if (nFilter == SfxStyleSearchBits::Auto) // automatic
1266
0
        nFilter = m_nAppFilter;
1267
1268
0
    OSL_ENSURE(m_pStyleSheetPool, "no StyleSheetPool");
1269
0
    if (!m_pStyleSheetPool)
1270
0
        return;
1271
1272
0
    m_aUpdateStyles.Call(nFlags);
1273
1274
0
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->First(eFam, nFilter);
1275
1276
0
    std::unique_ptr<weld::TreeIter> xEntry = m_xFmtLb->make_iterator();
1277
0
    std::vector<StyleTree_Impl> aStyles;
1278
1279
0
    comphelper::string::NaturalStringSorter aSorter(
1280
0
        ::comphelper::getProcessComponentContext(),
1281
0
        Application::GetSettings().GetLanguageTag().getLocale());
1282
1283
0
    while (pStyle)
1284
0
    {
1285
0
        aStyles.emplace_back(pStyle->GetName(), pStyle->GetParent(), pStyle->GetSpotlightId());
1286
0
        pStyle = m_pStyleSheetPool->Next();
1287
0
    }
1288
0
    OUString aUIName = getDefaultStyleName(eFam);
1289
1290
    // Paradoxically, with a list and non-Latin style names,
1291
    // sorting twice is faster than sorting once.
1292
    // The first sort has a cheap comparator, and gets the list into mostly-sorted order.
1293
    // Then the second sort needs to call its (much more expensive) comparator less often.
1294
0
    std::sort(aStyles.begin(), aStyles.end(),
1295
0
              [](const StyleTree_Impl& rLHS, const StyleTree_Impl& rRHS) {
1296
0
                  return rLHS.getName() < rRHS.getName();
1297
0
              });
1298
0
    std::sort(aStyles.begin(), aStyles.end(),
1299
0
              [&aSorter, &aUIName](const StyleTree_Impl& rLHSS, const StyleTree_Impl& rRHSS) {
1300
0
                  const OUString& rLHS = rLHSS.getName();
1301
0
                  const OUString& rRHS = rRHSS.getName();
1302
0
                  if (rRHS == aUIName)
1303
0
                      return false;
1304
0
                  if (rLHS == aUIName)
1305
0
                      return true; // default always first
1306
0
                  return aSorter.compare(rLHS, rRHS) < 0;
1307
0
              });
1308
1309
    // Fill the display box
1310
0
    m_xFmtLb->freeze();
1311
0
    m_xFmtLb->clear();
1312
1313
0
    SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1314
0
    StylesSpotlightColorMap* pSpotlightColorMap = nullptr;
1315
0
    bool bOrigMapHasEntries = false;
1316
0
    if (pViewShell && m_bModuleHasStylesSpotlightFeature)
1317
0
    {
1318
0
        if (eFam == SfxStyleFamily::Para)
1319
0
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightParaColorMap();
1320
0
        else if (eFam == SfxStyleFamily::Char)
1321
0
            pSpotlightColorMap = &pViewShell->GetStylesSpotlightCharColorMap();
1322
0
    }
1323
1324
0
    if (pSpotlightColorMap && !pSpotlightColorMap->empty())
1325
0
    {
1326
0
        bOrigMapHasEntries = true;
1327
0
        pSpotlightColorMap->clear();
1328
0
    }
1329
1330
0
    size_t nCount = aStyles.size();
1331
1332
0
    if (pViewShell && m_bModuleHasStylesSpotlightFeature
1333
0
        && ((eFam == SfxStyleFamily::Para && m_bSpotlightParaStyles)
1334
0
            || (eFam == SfxStyleFamily::Char && m_bSpotlightCharStyles)))
1335
0
    {
1336
0
        m_xFmtLb->bulk_insert_for_each(
1337
0
            nCount,
1338
0
            [this, &aStyles, eFam, pViewShell](weld::TreeIter& rIter, int nIdx) {
1339
0
                const OUString& rName = aStyles[nIdx].getName();
1340
0
                auto pChildStyle = m_pStyleSheetPool->Find(rName, eFam);
1341
0
                if (pChildStyle && pChildStyle->IsUsed())
1342
0
                    lcl_Update(*m_xFmtLb, rIter, aStyles[nIdx], eFam, pViewShell);
1343
0
                else
1344
0
                {
1345
0
                    m_xFmtLb->set_id(rIter, rName);
1346
0
                    m_xFmtLb->set_text(rIter, rName);
1347
0
                }
1348
0
            },
1349
0
            nullptr, nullptr, /*bGoingToSetText*/ true);
1350
0
    }
1351
0
    else
1352
0
    {
1353
0
        m_xFmtLb->bulk_insert_for_each(nCount,
1354
0
                                       [this, &aStyles](weld::TreeIter& rIter, int nIdx) {
1355
0
                                           const OUString& rName = aStyles[nIdx].getName();
1356
0
                                           m_xFmtLb->set_id(rIter, rName);
1357
0
                                           m_xFmtLb->set_text(rIter, rName);
1358
0
                                       },
1359
0
                                       nullptr, nullptr, /*bGoingToSetText*/ true);
1360
0
    }
1361
1362
0
    m_xFmtLb->columns_autosize();
1363
1364
0
    m_xFmtLb->thaw();
1365
1366
    // make view update
1367
0
    if (pViewShell && pSpotlightColorMap && (!pSpotlightColorMap->empty() || bOrigMapHasEntries))
1368
0
        static_cast<SfxListener*>(pViewShell)
1369
0
            ->Notify(*m_pStyleSheetPool, SfxHint(SfxHintId::StylesSpotlightModified));
1370
1371
    // Selects the current style if any
1372
0
    SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1373
0
    OUString aStyle;
1374
0
    if (pState)
1375
0
        aStyle = pState->GetStyleName();
1376
0
    m_pParentDialog->SelectStyle(aStyle, false, *this);
1377
0
    EnableDelete(nullptr);
1378
0
}
1379
1380
void StyleList::SetFamilyState(sal_uInt16 nSlotId, const SfxTemplateItem* pItem)
1381
0
{
1382
0
    sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START;
1383
0
    m_pFamilyState[nIdx].reset();
1384
0
    if (pItem)
1385
0
        m_pFamilyState[nIdx].reset(new SfxTemplateItem(*pItem));
1386
0
    m_bUpdateFamily = true;
1387
0
}
1388
1389
void StyleList::SetHierarchical()
1390
0
{
1391
0
    m_bHierarchical = true;
1392
0
    const OUString aSelectEntry(GetSelectedEntry());
1393
0
    m_xFmtLb->hide();
1394
0
    FillTreeBox(GetActualFamily());
1395
0
    m_pParentDialog->SelectStyle(aSelectEntry, false, *this);
1396
0
    m_xTreeBox->show();
1397
0
}
1398
1399
void StyleList::SetFilterControlsHandle()
1400
0
{
1401
0
    m_xTreeBox->hide();
1402
0
    m_xFmtLb->show();
1403
0
    m_bHierarchical = false;
1404
0
}
1405
1406
// Handler for the New-Buttons
1407
void StyleList::NewHdl()
1408
0
{
1409
0
    if (m_nActFamily == 0xffff
1410
0
        || !(m_xTreeBox->get_visible() || m_xFmtLb->count_selected_rows() <= 1))
1411
0
        return;
1412
1413
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1414
0
    const SfxStyleFamily eFam = pItem->GetFamily();
1415
0
    SfxStyleSearchBits nMask(SfxStyleSearchBits::Auto);
1416
0
    if (m_nActFilter != 0xffff)
1417
0
        nMask = pItem->GetFilterList()[m_nActFilter].nFlags;
1418
0
    if (nMask == SfxStyleSearchBits::Auto) // automatic
1419
0
        nMask = m_nAppFilter;
1420
1421
0
    m_pParentDialog->Execute_Impl(SID_STYLE_NEW, u""_ustr, GetSelectedEntry(),
1422
0
                                  static_cast<sal_uInt16>(eFam), *this, nMask);
1423
0
}
1424
1425
// Handler for the edit-Buttons
1426
void StyleList::EditHdl()
1427
0
{
1428
0
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1429
0
    {
1430
0
        sal_uInt16 nFilter = m_nActFilter;
1431
0
        OUString aTemplName(GetSelectedEntry());
1432
0
        GetSelectedStyle(); // -Wall required??
1433
0
        m_pParentDialog->Execute_Impl(SID_STYLE_EDIT, aTemplName, OUString(),
1434
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1435
0
                                      SfxStyleSearchBits::Auto, &nFilter);
1436
0
    }
1437
0
}
1438
1439
// Handler for the Delete-Buttons
1440
void StyleList::DeleteHdl()
1441
0
{
1442
0
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1443
0
        return;
1444
1445
0
    bool bUsedStyle = false; // one of the selected styles are used in the document?
1446
1447
0
    std::vector<std::unique_ptr<weld::TreeIter>> aList;
1448
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1449
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1450
1451
0
    OUStringBuffer aMsg(SfxResId(STR_DELETE_STYLE_USED) + SfxResId(STR_DELETE_STYLE));
1452
1453
0
    pTreeView->selected_foreach(
1454
0
        [this, pTreeView, pItem, &aList, &bUsedStyle, &aMsg](weld::TreeIter& rEntry) {
1455
0
            aList.emplace_back(pTreeView->make_iterator(&rEntry));
1456
            // check the style is used or not
1457
0
            const OUString aTemplName(pTreeView->get_text(rEntry));
1458
1459
0
            SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1460
1461
0
            if (pStyle->IsUsed()) // pStyle is in use in the document?
1462
0
            {
1463
0
                if (bUsedStyle) // add a separator for the second and later styles
1464
0
                    aMsg.append(", ");
1465
0
                aMsg.append(aTemplName);
1466
0
                bUsedStyle = true;
1467
0
            }
1468
1469
0
            return false;
1470
0
        });
1471
1472
0
    bool aApproved = false;
1473
1474
    // we only want to show the dialog once and if we want to delete a style in use (UX-advice)
1475
0
    if (bUsedStyle)
1476
0
    {
1477
0
        std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(
1478
0
            pTreeView, VclMessageType::Question, VclButtonsType::YesNo, aMsg.makeStringAndClear()));
1479
0
        aApproved = xBox->run() == RET_YES;
1480
0
    }
1481
1482
    // if there are no used styles selected or the user approved the changes
1483
0
    if (bUsedStyle && !aApproved)
1484
0
        return;
1485
1486
0
    for (auto const& elem : aList)
1487
0
    {
1488
0
        const OUString aTemplName(pTreeView->get_text(*elem));
1489
0
        m_bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting
1490
0
        m_pParentDialog->Execute_Impl(SID_STYLE_DELETE, aTemplName, OUString(),
1491
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1492
1493
0
        if (m_xTreeBox->get_visible())
1494
0
        {
1495
0
            weld::RemoveParentKeepChildren(*m_xTreeBox, *elem);
1496
0
            m_bDontUpdate = false;
1497
0
        }
1498
0
    }
1499
0
    m_bDontUpdate = false; // if everything is deleted set m_bDontUpdate back to false
1500
0
    UpdateStyles(StyleFlags::UpdateFamilyList); // and force-update the list
1501
0
}
1502
1503
void StyleList::HideHdl()
1504
0
{
1505
0
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1506
0
        return;
1507
1508
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1509
0
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1510
0
        OUString aTemplName = pTreeView->get_text(rEntry);
1511
1512
0
        m_pParentDialog->Execute_Impl(SID_STYLE_HIDE, aTemplName, OUString(),
1513
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1514
1515
0
        return false;
1516
0
    });
1517
0
}
1518
1519
void StyleList::ShowHdl()
1520
0
{
1521
0
    if (m_nActFamily == 0xffff || !HasSelectedStyle(nullptr))
1522
0
        return;
1523
1524
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1525
0
    pTreeView->selected_foreach([this, pTreeView](weld::TreeIter& rEntry) {
1526
0
        OUString aTemplName = pTreeView->get_text(rEntry);
1527
1528
0
        m_pParentDialog->Execute_Impl(SID_STYLE_SHOW, aTemplName, OUString(),
1529
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this);
1530
1531
0
        return false;
1532
0
    });
1533
0
}
1534
1535
IMPL_LINK_NOARG(StyleList, EnableDelete, void*, void)
1536
0
{
1537
0
    bool bEnableDelete(false);
1538
0
    if (m_nActFamily != 0xffff && HasSelectedStyle(nullptr))
1539
0
    {
1540
0
        OSL_ENSURE(m_pStyleSheetPool, "No StyleSheetPool");
1541
0
        const OUString aTemplName(GetSelectedEntry());
1542
0
        const SfxStyleFamilyItem* pItem = GetFamilyItem();
1543
0
        const SfxStyleFamily eFam = pItem->GetFamily();
1544
0
        SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto;
1545
0
        if (pItem->GetFilterList().size() > m_nActFilter)
1546
0
            nFilter = pItem->GetFilterList()[m_nActFilter].nFlags;
1547
0
        if (nFilter == SfxStyleSearchBits::Auto) // automatic
1548
0
            nFilter = m_nAppFilter;
1549
0
        const SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(
1550
0
            aTemplName, eFam, m_xTreeBox->get_visible() ? SfxStyleSearchBits::All : nFilter);
1551
1552
0
        OSL_ENSURE(pStyle, "Style not found");
1553
0
        if (pStyle && pStyle->IsUserDefined())
1554
0
        {
1555
0
            if (pStyle->HasClearParentSupport() || !pStyle->IsUsed())
1556
0
            {
1557
0
                bEnableDelete = true;
1558
0
            }
1559
0
        }
1560
0
    }
1561
0
    m_pParentDialog->EnableDel(bEnableDelete, this);
1562
0
}
1563
1564
IMPL_LINK_NOARG(StyleList, Clear, void*, void)
1565
0
{
1566
0
    if (m_pCurObjShell && m_bModuleHasStylesSpotlightFeature)
1567
0
    {
1568
0
        SfxViewShell* pViewShell = m_pCurObjShell->GetViewShell();
1569
0
        if (pViewShell)
1570
0
        {
1571
0
            pViewShell->GetStylesSpotlightParaColorMap().clear();
1572
0
            pViewShell->GetStylesSpotlightCharColorMap().clear();
1573
0
        }
1574
0
    }
1575
0
    m_aStyleFamilies.clear();
1576
0
    for (auto& i : m_pFamilyState)
1577
0
        i.reset();
1578
0
    m_pCurObjShell = nullptr;
1579
0
    for (auto& i : pBoundItems)
1580
0
        i.reset();
1581
0
}
1582
1583
0
IMPL_LINK(StyleList, OnPopupEnd, const OUString&, sCommand, void) { MenuSelect(sCommand); }
1584
1585
void StyleList::ShowMenu(const CommandEvent& rCEvt)
1586
0
{
1587
0
    CreateContextMenu();
1588
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1589
0
    mxMenu->connect_activate(LINK(this, StyleList, OnPopupEnd));
1590
0
    mxMenu->popup_at_rect(pTreeView, tools::Rectangle(rCEvt.GetMousePosPixel(), Size(1, 1)));
1591
0
}
1592
1593
void StyleList::MenuSelect(const OUString& rIdent)
1594
0
{
1595
0
    sLastItemIdent = rIdent;
1596
0
    if (sLastItemIdent.isEmpty())
1597
0
        return;
1598
0
    Application::PostUserEvent(LINK(this, StyleList, MenuSelectAsyncHdl)); /***check this****/
1599
0
}
1600
1601
void StyleList::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint)
1602
0
{
1603
0
    const SfxHintId nId = rHint.GetId();
1604
1605
0
    switch (nId)
1606
0
    {
1607
0
        case SfxHintId::UpdateDone:
1608
0
        {
1609
0
            SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1610
0
            SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1611
0
            if (m_pParentDialog->GetNotifyUpdate()
1612
0
                && (!m_pParentDialog->IsCheckedItem(u"watercan"_ustr)
1613
0
                    || (pDocShell && pDocShell->GetStyleSheetPool() != m_pStyleSheetPool)))
1614
0
            {
1615
0
                m_pParentDialog->SetNotifyupdate(false);
1616
0
                Update();
1617
0
            }
1618
0
            else if (m_bUpdateFamily)
1619
0
            {
1620
0
                UpdateFamily();
1621
0
                m_aUpdateFamily.Call(*this);
1622
0
            }
1623
1624
0
            if (m_pStyleSheetPool)
1625
0
            {
1626
0
                OUString aStr = GetSelectedEntry();
1627
0
                if (!aStr.isEmpty())
1628
0
                {
1629
0
                    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1630
0
                    if (!pItem)
1631
0
                        break;
1632
0
                    const SfxStyleFamily eFam = pItem->GetFamily();
1633
0
                    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aStr, eFam);
1634
0
                    if (pStyle)
1635
0
                    {
1636
0
                        bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly);
1637
0
                        m_pParentDialog->EnableEdit(bReadWrite, this);
1638
0
                        m_pParentDialog->EnableHide(
1639
0
                            bReadWrite && !pStyle->IsUsed() && !pStyle->IsHidden(), this);
1640
0
                        m_pParentDialog->EnableShow(bReadWrite && pStyle->IsHidden(), this);
1641
0
                    }
1642
0
                    else
1643
0
                    {
1644
0
                        m_pParentDialog->EnableEdit(false, this);
1645
0
                        m_pParentDialog->EnableHide(false, this);
1646
0
                        m_pParentDialog->EnableShow(false, this);
1647
0
                    }
1648
0
                }
1649
0
            }
1650
0
            break;
1651
0
        }
1652
1653
        // Necessary if switching between documents and in both documents
1654
        // the same template is used. Do not immediately call Update_Impl,
1655
        // for the case that one of the documents is an internal InPlaceObject!
1656
0
        case SfxHintId::DocChanged:
1657
0
            m_pParentDialog->SetNotifyupdate(true);
1658
0
            break;
1659
0
        case SfxHintId::Dying:
1660
0
        {
1661
0
            EndListening(*m_pStyleSheetPool);
1662
0
            m_pStyleSheetPool = nullptr;
1663
0
            break;
1664
0
        }
1665
0
        default:
1666
0
            break;
1667
0
    }
1668
1669
    // Do not set timer when the stylesheet pool is in the box, because it is
1670
    // possible that a new one is registered after the timer is up -
1671
    // works bad in UpdateStyles_Impl ()!
1672
1673
0
    if (!m_bDontUpdate && nId != SfxHintId::Dying
1674
0
        && (nId == SfxHintId::SfxStyleSheetPool || dynamic_cast<const SfxStyleSheetHint*>(&rHint)
1675
0
            || nId == SfxHintId::StyleSheetModifiedExtended)) // ie. SfxStyleSheetModifiedHint
1676
0
    {
1677
0
        if (!pIdle)
1678
0
        {
1679
0
            pIdle.reset(new Idle("SfxCommonTemplate"));
1680
0
            pIdle->SetPriority(TaskPriority::LOWEST);
1681
0
            pIdle->SetInvokeHandler(LINK(this, StyleList, TimeOut));
1682
0
        }
1683
0
        pIdle->Start();
1684
0
    }
1685
0
}
1686
1687
IMPL_LINK_NOARG(StyleList, TimeOut, Timer*, void)
1688
0
{
1689
0
    if (!m_bDontUpdate)
1690
0
    {
1691
0
        m_bDontUpdate = true;
1692
0
        if (!m_xTreeBox->get_visible())
1693
0
            UpdateStyles(StyleFlags::UpdateFamilyList);
1694
0
        else
1695
0
        {
1696
0
            FillTreeBox(GetActualFamily());
1697
0
            SfxTemplateItem* pState = m_pFamilyState[m_nActFamily - 1].get();
1698
0
            if (pState)
1699
0
            {
1700
0
                m_pParentDialog->SelectStyle(pState->GetStyleName(), false, *this);
1701
0
                EnableDelete(nullptr);
1702
0
            }
1703
0
        }
1704
0
        m_bDontUpdate = false;
1705
0
        pIdle.reset();
1706
0
    }
1707
0
    else
1708
0
        pIdle->Start();
1709
0
}
1710
1711
IMPL_LINK_NOARG(StyleList, MenuSelectAsyncHdl, void*, void)
1712
0
{
1713
0
    if (sLastItemIdent == "new")
1714
0
        NewHdl();
1715
0
    else if (sLastItemIdent == "edit")
1716
0
        EditHdl();
1717
0
    else if (sLastItemIdent == "delete")
1718
0
        DeleteHdl();
1719
0
    else if (sLastItemIdent == "hide")
1720
0
        HideHdl();
1721
0
    else if (sLastItemIdent == "show")
1722
0
        ShowHdl();
1723
1724
0
    mxMenu.reset();
1725
0
    mxMenuBuilder.reset();
1726
0
}
1727
1728
// Double-click on a style sheet in the ListBox is applied.
1729
IMPL_LINK(StyleList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
1730
0
{
1731
0
    rUnsetDragIcon = false;
1732
    // Allow normal processing. only if bAllowReParentDrop is true
1733
0
    return !m_bAllowReParentDrop;
1734
0
}
1735
1736
IMPL_LINK(StyleList, KeyInputHdl, const KeyEvent&, rKeyEvent, bool)
1737
0
{
1738
0
    bool bRet = false;
1739
0
    const vcl::KeyCode& rKeyCode = rKeyEvent.GetKeyCode();
1740
0
    if (m_bCanDel && !rKeyCode.GetModifier() && rKeyCode.GetCode() == KEY_DELETE)
1741
0
    {
1742
0
        DeleteHdl();
1743
0
        bRet = true;
1744
0
    }
1745
0
    return bRet;
1746
0
}
1747
1748
IMPL_LINK(StyleList, QueryTooltipHdl, const weld::TreeIter&, rEntry, OUString)
1749
0
{
1750
0
    weld::TreeView* pTreeView = m_xTreeBox->get_visible() ? m_xTreeBox.get() : m_xFmtLb.get();
1751
0
    const OUString aTemplName(pTreeView->get_text(rEntry));
1752
0
    OUString sQuickHelpText(aTemplName);
1753
1754
0
    const SfxStyleFamilyItem* pItem = GetFamilyItem();
1755
0
    if (!pItem)
1756
0
        return sQuickHelpText;
1757
0
    SfxStyleSheetBase* pStyle = m_pStyleSheetPool->Find(aTemplName, pItem->GetFamily());
1758
0
    if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document?
1759
0
    {
1760
0
        OUString sUsedBy;
1761
0
        if (pStyle->GetFamily() == SfxStyleFamily::Pseudo)
1762
0
            sUsedBy = pStyle->GetUsedBy();
1763
1764
0
        if (!sUsedBy.isEmpty())
1765
0
        {
1766
0
            const sal_Int32 nMaxLen = 80;
1767
0
            if (sUsedBy.getLength() > nMaxLen)
1768
0
            {
1769
0
                sUsedBy = OUString::Concat(sUsedBy.subView(0, nMaxLen)) + "...";
1770
0
            }
1771
1772
0
            OUString aMessage = SfxResId(STR_STYLEUSEDBY);
1773
0
            aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy);
1774
0
            sQuickHelpText = aTemplName + " " + aMessage;
1775
0
        }
1776
0
    }
1777
1778
0
    return sQuickHelpText;
1779
0
}
1780
1781
IMPL_LINK(StyleList, CustomRenderHdl, weld::TreeView::render_args, aPayload, void)
1782
0
{
1783
0
    vcl::RenderContext& rRenderContext = std::get<0>(aPayload);
1784
0
    const ::tools::Rectangle& rRect = std::get<1>(aPayload);
1785
0
    ::tools::Rectangle aRect(
1786
0
        rRect.TopLeft(),
1787
0
        Size(rRenderContext.GetOutputSize().Width() - rRect.Left(), rRect.GetHeight()));
1788
0
    bool bSelected = comphelper::LibreOfficeKit::isActive() ? false : std::get<2>(aPayload);
1789
0
    const OUString& rId = std::get<3>(aPayload);
1790
1791
0
    auto popIt = rRenderContext.ScopedPush(vcl::PushFlags::TEXTCOLOR);
1792
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1793
0
    if (bSelected)
1794
0
        rRenderContext.SetTextColor(rStyleSettings.GetHighlightTextColor());
1795
0
    else
1796
0
        rRenderContext.SetTextColor(rStyleSettings.GetDialogTextColor());
1797
1798
0
    bool bSuccess = false;
1799
1800
0
    SfxObjectShell* pShell = SfxObjectShell::Current();
1801
0
    sfx2::StyleManager* pStyleManager = pShell ? pShell->GetStyleManager() : nullptr;
1802
1803
0
    if (pStyleManager)
1804
0
    {
1805
0
        if (const SfxStyleFamilyItem* pItem = GetFamilyItem())
1806
0
        {
1807
0
            SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(rId, pItem->GetFamily());
1808
1809
0
            if (pStyleSheet)
1810
0
            {
1811
0
                auto popIt2 = rRenderContext.ScopedPush(vcl::PushFlags::ALL);
1812
                // tdf#119919 - show "hidden" styles as disabled to not move children onto root node
1813
0
                if (pStyleSheet->IsHidden() && m_bHierarchical)
1814
0
                    rRenderContext.SetTextColor(rStyleSettings.GetDisableColor());
1815
1816
0
                sal_Int32 nSize = aRect.GetHeight();
1817
0
                std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer(
1818
0
                    pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize));
1819
0
                bSuccess
1820
0
                    = pStylePreviewRenderer->recalculate() && pStylePreviewRenderer->render(aRect);
1821
0
            }
1822
0
        }
1823
0
    }
1824
1825
0
    if (!bSuccess)
1826
0
        rRenderContext.DrawText(aRect, rId, DrawTextFlags::Left | DrawTextFlags::VCenter);
1827
0
}
1828
1829
// Selection of a template during the Watercan-Status
1830
IMPL_LINK(StyleList, FmtSelectHdl, weld::TreeView&, rListBox, void)
1831
0
{
1832
0
    std::unique_ptr<weld::TreeIter> xHdlEntry = rListBox.make_iterator();
1833
0
    if (!rListBox.get_cursor(xHdlEntry.get()))
1834
0
        return;
1835
1836
0
    m_pParentDialog->SelectStyle(rListBox.get_text(*xHdlEntry), true, *this);
1837
0
}
1838
1839
IMPL_LINK_NOARG(StyleList, TreeListApplyHdl, weld::TreeView&, bool)
1840
0
{
1841
    // only if that region is allowed
1842
0
    if (m_nActFamily != 0xffff && nullptr != m_pFamilyState[m_nActFamily - 1]
1843
0
        && !GetSelectedEntry().isEmpty())
1844
0
    {
1845
0
        m_pParentDialog->Execute_Impl(SID_STYLE_APPLY, GetSelectedEntry(), OUString(),
1846
0
                                      static_cast<sal_uInt16>(GetFamilyItem()->GetFamily()), *this,
1847
0
                                      SfxStyleSearchBits::Auto, nullptr, &m_nModifier);
1848
0
    }
1849
    // After selecting a focused item if possible again on the app window
1850
0
    if (dynamic_cast<const SfxTemplateDialog_Impl*>(m_pParentDialog) != nullptr)
1851
0
    {
1852
0
        SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1853
0
        SfxViewShell* pVu = pViewFrame->GetViewShell();
1854
0
        vcl::Window* pAppWin = pVu ? pVu->GetWindow() : nullptr;
1855
0
        if (pAppWin)
1856
0
            pAppWin->GrabFocus();
1857
0
    }
1858
1859
0
    return true;
1860
0
}
1861
1862
IMPL_LINK(StyleList, MousePressHdl, const MouseEvent&, rMEvt, bool)
1863
0
{
1864
0
    m_nModifier = rMEvt.GetModifier();
1865
0
    return false;
1866
0
}
1867
1868
// Notice from SfxBindings that the update is completed. Pushes out the update
1869
// of the display.
1870
void StyleList::Update()
1871
0
{
1872
0
    bool bDocChanged = false;
1873
0
    SfxStyleSheetBasePool* pNewPool = nullptr;
1874
0
    SfxViewFrame* pViewFrame = m_pBindings->GetDispatcher_Impl()->GetFrame();
1875
0
    SfxObjectShell* pDocShell = pViewFrame->GetObjectShell();
1876
0
    if (pDocShell)
1877
0
        pNewPool = pDocShell->GetStyleSheetPool();
1878
1879
0
    if (pNewPool != m_pStyleSheetPool && pDocShell)
1880
0
    {
1881
0
        SfxModule* pNewModule = pDocShell->GetModule();
1882
0
        if (pNewModule && pNewModule != m_Module)
1883
0
        {
1884
0
            m_aClearResource.Call(nullptr);
1885
0
            m_aReadResource.Call(*this);
1886
0
        }
1887
0
        if (m_pStyleSheetPool)
1888
0
        {
1889
0
            EndListening(*m_pStyleSheetPool);
1890
0
            m_pStyleSheetPool = nullptr;
1891
0
        }
1892
1893
0
        if (pNewPool)
1894
0
        {
1895
0
            StartListening(*pNewPool);
1896
0
            m_pStyleSheetPool = pNewPool;
1897
0
            bDocChanged = true;
1898
0
        }
1899
0
    }
1900
1901
0
    if (m_bUpdateFamily)
1902
0
    {
1903
0
        UpdateFamily();
1904
0
        m_aUpdateFamily.Call(*this);
1905
0
    }
1906
1907
0
    sal_uInt16 i;
1908
0
    for (i = 0; i < MAX_FAMILIES; ++i)
1909
0
        if (m_pFamilyState[i])
1910
0
            break;
1911
0
    if (i == MAX_FAMILIES || !pNewPool)
1912
        // nothing is allowed
1913
0
        return;
1914
1915
0
    SfxTemplateItem* pItem = nullptr;
1916
    // current region not within the allowed region or default
1917
0
    if (m_nActFamily == 0xffff || nullptr == (pItem = m_pFamilyState[m_nActFamily - 1].get()))
1918
0
    {
1919
0
        m_pParentDialog->CheckItem(OUString::number(m_nActFamily), false);
1920
0
        const size_t nFamilyCount = m_aStyleFamilies.size();
1921
0
        size_t n;
1922
0
        for (n = 0; n < nFamilyCount; n++)
1923
0
            if (m_pFamilyState[StyleNrToInfoOffset(n)])
1924
0
                break;
1925
1926
0
        std::unique_ptr<SfxTemplateItem>& pNewItem = m_pFamilyState[StyleNrToInfoOffset(n)];
1927
0
        m_nAppFilter = pNewItem->GetValue();
1928
0
        m_pParentDialog->FamilySelect(StyleNrToInfoOffset(n) + 1, *this);
1929
0
        pItem = pNewItem.get();
1930
0
    }
1931
0
    else if (bDocChanged)
1932
0
    {
1933
        // other DocShell -> all new
1934
0
        m_pParentDialog->CheckItem(OUString::number(m_nActFamily));
1935
0
        m_nActFilter = static_cast<sal_uInt16>(m_aLoadFactoryStyleFilter.Call(pDocShell));
1936
0
        m_pParentDialog->IsUpdate(*this);
1937
0
        if (0xffff == m_nActFilter)
1938
0
        {
1939
0
            m_nActFilter = pDocShell->GetAutoStyleFilterIndex();
1940
0
        }
1941
1942
0
        m_nAppFilter = pItem->GetValue();
1943
0
        if (!m_xTreeBox->get_visible())
1944
0
        {
1945
0
            UpdateStyles(StyleFlags::UpdateFamilyList);
1946
0
        }
1947
0
        else
1948
0
            FillTreeBox(GetActualFamily());
1949
0
    }
1950
0
    else
1951
0
    {
1952
        // other filters for automatic
1953
0
        m_pParentDialog->CheckItem(OUString::number(m_nActFamily));
1954
0
        const SfxStyleFamilyItem* pStyleItem = GetFamilyItem();
1955
0
        if (pStyleItem
1956
0
            && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[m_nActFilter].nFlags
1957
0
            && m_nAppFilter != pItem->GetValue())
1958
0
        {
1959
0
            m_nAppFilter = pItem->GetValue();
1960
0
            if (!m_xTreeBox->get_visible())
1961
0
                UpdateStyles(StyleFlags::UpdateFamilyList);
1962
0
            else
1963
0
                FillTreeBox(GetActualFamily());
1964
0
        }
1965
0
        else
1966
0
        {
1967
0
            m_nAppFilter = pItem->GetValue();
1968
0
        }
1969
0
    }
1970
0
    const OUString aStyle(pItem->GetStyleName());
1971
0
    m_pParentDialog->SelectStyle(aStyle, false, *this);
1972
0
    EnableDelete(nullptr);
1973
0
    m_pParentDialog->EnableNew(m_bCanNew, this);
1974
0
}
1975
1976
const SfxStyleFamilyItem& StyleList::GetFamilyItemByIndex(size_t i) const
1977
0
{
1978
0
    return m_aStyleFamilies.at(i);
1979
0
}
1980
1981
IMPL_STATIC_LINK(StyleList, CustomGetSizeHdl, weld::TreeView::get_size_args, aPayload, Size)
1982
0
{
1983
0
    vcl::RenderContext& rRenderContext = aPayload.first;
1984
0
    return Size(comphelper::LibreOfficeKit::isActive() ? 200 : 42,
1985
0
                32 * rRenderContext.GetDPIScaleFactor());
1986
0
}
1987
1988
IMPL_LINK(StyleList, PopupFlatMenuHdl, const CommandEvent&, rCEvt, bool)
1989
0
{
1990
0
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
1991
0
        return false;
1992
1993
0
    PrepareMenu(rCEvt.GetMousePosPixel());
1994
1995
0
    if (m_xFmtLb->count_selected_rows() <= 0)
1996
0
    {
1997
0
        m_pParentDialog->EnableEdit(false, this);
1998
0
        m_pParentDialog->EnableDel(false, this);
1999
0
    }
2000
2001
0
    ShowMenu(rCEvt);
2002
2003
0
    return true;
2004
0
}
2005
2006
IMPL_LINK(StyleList, PopupTreeMenuHdl, const CommandEvent&, rCEvt, bool)
2007
0
{
2008
0
    if (rCEvt.GetCommand() != CommandEventId::ContextMenu)
2009
0
        return false;
2010
2011
0
    PrepareMenu(rCEvt.GetMousePosPixel());
2012
2013
0
    ShowMenu(rCEvt);
2014
2015
0
    return true;
2016
0
}
2017
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */