summaryrefslogtreecommitdiff
path: root/sw/inc/frameformats.hxx
blob: 97c86408e867a343a03705ceffeac8955a7f4c06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
/* -*- 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 .
 */
#pragma once

#include "docary.hxx"
#include "swtblfmt.hxx"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/tag.hpp>

class SwFrameFormat;
class SwTableFormat;

// Like o3tl::find_partialorder_ptrequals
// We don't allow duplicated object entries!
struct type_name_key
    : boost::multi_index::composite_key<
          SwFrameFormat*,
          boost::multi_index::const_mem_fun<SwFormat, const OUString&, &SwFormat::GetName>,
          boost::multi_index::const_mem_fun<SwFormat, sal_uInt16, &SwFormat::Which>,
          boost::multi_index::identity<SwFrameFormat*> // the actual object pointer
          >
{
};

typedef boost::multi_index_container<
    SwFrameFormat*,
    boost::multi_index::indexed_by<boost::multi_index::random_access<>,
                                   boost::multi_index::ordered_unique<type_name_key>>>
    SwFrameFormatsBase;

/// Specific frame formats (frames, DrawObjects).
class SW_DLLPUBLIC SwFrameFormats final : public SwFormatsBase
{
    // function updating ByName index via modify
    friend void SwFrameFormat::SetFormatName(const OUString&, bool);

public:
    typedef SwFrameFormatsBase::nth_index<0>::type ByPos;
    typedef SwFrameFormatsBase::nth_index<1>::type ByTypeAndName;
    typedef ByPos::iterator iterator;

private:
    SwFrameFormatsBase m_Array;
    ByPos& m_PosIndex;
    ByTypeAndName& m_TypeAndNameIndex;

public:
    typedef ByPos::const_iterator const_iterator;
    typedef SwFrameFormatsBase::size_type size_type;
    typedef SwFrameFormatsBase::value_type value_type;

    SwFrameFormats();
    // frees all SwFrameFormat!
    virtual ~SwFrameFormats() override;

    bool empty() const { return m_Array.empty(); }
    size_t size() const { return m_Array.size(); }

    // Only fails, if you try to insert the same object twice
    std::pair<const_iterator, bool> push_back(const value_type& x);

    // This will try to remove the exact object!
    bool erase(const value_type& x);
    void erase(size_type index);
    void erase(const_iterator const& position);

    // Get the iterator of the exact object (includes pointer!),
    // e.g for position with std::distance.
    // There is also ContainsFormat, if you don't need the position.
    const_iterator find(const value_type& x) const;

    ByTypeAndName::const_iterator findByTypeAndName(sal_uInt16 type, const OUString& name) const;
    // search for formats by name
    std::pair<ByTypeAndName::const_iterator, ByTypeAndName::const_iterator>
    findRangeByName(const OUString& name) const;
    // So we can actually check for end()
    ByTypeAndName::const_iterator typeAndNameEnd() const { return m_TypeAndNameIndex.end(); }

    const value_type& operator[](size_t index_) const { return m_PosIndex.operator[](index_); }
    const value_type& front() const { return m_PosIndex.front(); }
    const value_type& back() const { return m_PosIndex.back(); }
    const_iterator begin() const { return m_PosIndex.begin(); }
    const_iterator end() const { return m_PosIndex.end(); }

    void dumpAsXml(xmlTextWriterPtr pWriter, const char* pName) const;

    virtual size_t GetFormatCount() const override { return m_Array.size(); }
    virtual SwFormat* GetFormat(size_t idx) const override { return operator[](idx); }
    virtual void Rename(const SwFrameFormat& rFormat, const OUString& sNewName) override;

    /// fast check if given format is contained here
    /// @precond pFormat must not have been deleted
    bool ContainsFormat(SwFrameFormat const& rFormat) const;
    /// not so fast check that given format is still alive (i.e. contained here)
    bool IsAlive(SwFrameFormat const*) const;

    void DeleteAndDestroyAll(bool keepDefault = false);

    bool newDefault(const value_type& x);
    void newDefault(const_iterator const& position);

    // Override return type to reduce casting
    virtual SwFrameFormat* FindFormatByName(const OUString& rName) const override;
};

namespace sw
{
template <class value_type> class FrameFormats final : public SwFormatsBase
{
    struct ByPos
    {
    };
    struct ByTypeAndName
    {
    };
    struct FrameFormatsKey
        : boost::multi_index::composite_key<
              value_type,
              boost::multi_index::const_mem_fun<SwFormat, const OUString&, &SwFormat::GetName>,
              boost::multi_index::const_mem_fun<SwFormat, sal_uInt16, &SwFormat::Which>,
              boost::multi_index::identity<value_type> // the actual object pointer
              >
    {
    };
    typedef boost::multi_index_container<
        value_type, boost::multi_index::indexed_by<
                        boost::multi_index::random_access<boost::multi_index::tag<ByPos>>,
                        boost::multi_index::ordered_unique<boost::multi_index::tag<ByTypeAndName>,
                                                           FrameFormatsKey>>>
        FrameFormatsContainer;
    // function updating ByName index via modify
    friend class ::SwFrameFormat;

public:
    typedef typename FrameFormatsContainer::size_type size_type;
    typedef typename FrameFormatsContainer::template index<ByPos>::type index_type;
    typedef typename index_type::iterator iterator;
    typedef typename index_type::const_iterator const_iterator;
    typedef typename FrameFormatsContainer::template index<ByTypeAndName>::type name_index_type;
    typedef typename name_index_type::iterator name_iterator;
    typedef typename name_index_type::const_iterator const_name_iterator;
    typedef typename std::pair<const_name_iterator, const_name_iterator> range_type;

private:
    FrameFormatsContainer m_vContainer;
    index_type& GetByPos() { return m_vContainer.template get<ByPos>(); }
    name_index_type& GetByTypeAndName() { return m_vContainer.template get<ByTypeAndName>(); }
    const index_type& GetByPos() const { return m_vContainer.template get<ByPos>(); }
    const name_index_type& GetByTypeAndName() const
    {
        return m_vContainer.template get<ByTypeAndName>();
    }

public:
    FrameFormats(){};
    // frees all SwFrameFormat!
    virtual ~FrameFormats() override { DeleteAndDestroyAll(); };

    bool empty() const { return m_vContainer.empty(); }
    size_t size() const { return m_vContainer.size(); }

    // Only fails, if you try to insert the same object twice
    std::pair<const_iterator, bool> push_back(const value_type& x)
    {
        SAL_WARN_IF(x->m_ffList != nullptr, "sw.core", "Inserting already assigned item");
        assert(x->m_ffList == nullptr);
        x->m_ffList = this;
        return GetByPos().push_back(const_cast<value_type>(x));
    };

    // This will try to remove the exact object!
    bool erase(const value_type& x)
    {
        const_iterator const ret = find(x);
        SAL_WARN_IF(x->m_ffList != this, "sw.core", "Removing invalid / unassigned item");
        if (ret != end())
        {
            assert(x == *ret);
            x->m_ffList = nullptr;
            GetByPos().erase(ret);
            return true;
        }
        return false;
    };
    void erase(size_type index) { erase(begin() + index); };
    void erase(const_iterator const& position)
    {
        (*position)->m_ffList = nullptr;
        GetByPos().erase(begin() + (position - begin()));
    }

    // Get the iterator of the exact object (includes pointer!),
    // e.g for position with std::distance.
    // There is also ContainsFormat, if you don't need the position.
    const_iterator find(const value_type& x) const
    {
        auto it = GetByTypeAndName().find(std::make_tuple(x->GetName(), x->Which(), x));
        return m_vContainer.template project<ByPos>(it);
    };

    const_name_iterator findByTypeAndName(sal_uInt16 type, const OUString& name) const
    {
        return GetByTypeAndName().find(std::make_tuple(name, type));
    };
    // search for formats by name
    range_type findRangeByName(const OUString& rName) const
    {
        auto& idx = GetByTypeAndName();
        auto it = idx.lower_bound(std::make_tuple(rName, sal_uInt16(0)));
        auto itEnd = idx.upper_bound(std::make_tuple(rName, SAL_MAX_UINT16));
        return { it, itEnd };
    };
    // So we can actually check for end()
    const_name_iterator typeAndNameEnd() const { return GetByTypeAndName().end(); }

    const value_type& operator[](size_t index) const { return GetByPos().operator[](index); }
    const value_type& front() const { return GetByPos().front(); }
    const value_type& back() const { return GetByPos().back(); }
    const_iterator begin() const { return GetByPos().begin(); }
    const_iterator end() const { return GetByPos().end(); }

    void dumpAsXml(xmlTextWriterPtr pWriter, const char*) const
    {
        // TODO
        //(void)xmlTextWriterStartElement(pWriter, BAD_CAST(pName));
        for (const auto pFormat : GetByPos())
            pFormat->dumpAsXml(pWriter);
        //(void)xmlTextWriterEndElement(pWriter);
    };

    virtual size_t GetFormatCount() const override { return m_vContainer.size(); }
    virtual SwFormat* GetFormat(size_t idx) const override
    {
        return const_cast<value_type&>(operator[](idx));
    };
    virtual void Rename(const SwFrameFormat& rFormat, const OUString& sNewName) override
    {
        assert(dynamic_cast<value_type>(const_cast<SwFrameFormat*>(&rFormat)));
        iterator it = find(static_cast<value_type>(const_cast<SwFrameFormat*>(&rFormat)));
        assert(end() != it);
        const auto sOldName = rFormat.GetName();
        auto fRenamer
            = [sNewName](SwFormat* pFormat) { pFormat->SwFormat::SetFormatName(sNewName, false); };
        auto fRenamerUndo
            = [sOldName](SwFormat* pFormat) { pFormat->SwFormat::SetFormatName(sOldName, false); };
        bool const renamed = GetByPos().modify(it, fRenamer, fRenamerUndo);
        assert(renamed);
        (void)renamed; // unused in NDEBUG
    };

    /// fast check if given format is contained here
    /// @precond pFormat must not have been deleted
    bool ContainsFormat(const value_type& rpFormat) const { return rpFormat->m_ffList == this; };

    /// not so fast check that given format is still alive (i.e. contained here)
    bool IsAlive(value_type const* p) const { return find(*p) != end(); };

    void DeleteAndDestroyAll(bool keepDefault = false)
    {
        if (empty())
            return;
        const int offset = keepDefault ? 1 : 0;
        for (const_iterator it = begin() + offset; it != end(); ++it)
            delete *it;
        if (offset)
            GetByPos().erase(begin() + offset, end());
        else
            m_vContainer.clear();
    };

    bool newDefault(const value_type& x)
    {
        std::pair<iterator, bool> res = GetByPos().push_front(const_cast<value_type&>(x));
        if (!res.second)
            newDefault(res.first);
        return res.second;
    };
    void newDefault(const_iterator const& position)
    {
        if (position == begin())
            return;
        GetByPos().relocate(begin(), position);
    };

    // Override return type to reduce casting
    value_type FindFrameFormatByName(const OUString& rName) const
    {
        auto& idx = GetByTypeAndName();
        auto it = idx.lower_bound(std::make_tuple(rName, sal_uInt16(0)));
        if (it != idx.end() && (*it)->GetName() == rName)
            return *it;
        return nullptr;
    };
};
typedef FrameFormats<::SwTableFormat*> TableFrameFormats;
}

template class SW_DLLPUBLIC sw::FrameFormats<SwTableFormat*>;

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */