summaryrefslogtreecommitdiff
path: root/svx/source/sdr/contact/viewcontact.cxx
blob: 4c18c8bff9d44c703b1929f680856a73926185ec (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
322
323
324
325
326
327
328
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include <svx/sdr/contact/viewcontact.hxx>
#include <svx/sdr/contact/viewobjectcontact.hxx>
#include <svx/sdr/contact/objectcontact.hxx>
#include <basegfx/polygon/b2dpolygon.hxx>
#include <basegfx/polygon/b2dpolygontools.hxx>
#include <basegfx/color/bcolor.hxx>
#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
#include <basegfx/matrix/b2dhommatrix.hxx>
#include <svx/sdr/contact/objectcontactofpageview.hxx>
#include <tools/debug.hxx>

//////////////////////////////////////////////////////////////////////////////

namespace sdr
{
    namespace contact
    {
        // Create a Object-Specific ViewObjectContact, set ViewContact and
        // ObjectContact. Always needs to return something. Default is to create
        // a standard ViewObjectContact containing the given ObjectContact and *this
        ViewObjectContact& ViewContact::CreateObjectSpecificViewObjectContact(ObjectContact& rObjectContact)
        {
            return *(new ViewObjectContact(rObjectContact, *this));
        }

        ViewContact::ViewContact()
        :   maViewObjectContactVector(),
            mxViewIndependentPrimitive2DSequence()
        {
        }

        // Methods to react on start getting viewed or stop getting
        // viewed. This info is derived from the count of members of
        // registered ViewObjectContacts. Default does nothing.
        void ViewContact::StartGettingViewed()
        {
        }

        void ViewContact::StopGettingViewed()
        {
        }

        ViewContact::~ViewContact()
        {
            deleteAllVOCs();
        }

        void ViewContact::deleteAllVOCs()
        {
            // get rid of all VOCs
            // #i84257# To avoid that each 'delete pCandidate' again uses
            // the local RemoveViewObjectContact with a search and removal in the
            // vector, simply copy and clear local vector.
            std::vector< ViewObjectContact* > aLocalVOCList(maViewObjectContactVector);
            maViewObjectContactVector.clear();

            while(!aLocalVOCList.empty())
            {
                ViewObjectContact* pCandidate = aLocalVOCList.back();
                aLocalVOCList.pop_back();
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList in VC (!)");

                // ViewObjectContacts only make sense with View and Object contacts.
                // When the contact to the SdrObject is deleted like in this case,
                // all ViewObjectContacts can be deleted, too.
                delete pCandidate;
            }

            // assert when there were new entries added during deletion
            DBG_ASSERT(maViewObjectContactVector.empty(), "Corrupted ViewObjectContactList in VC (!)");
        }

        // get a Object-specific ViewObjectContact for a specific
        // ObjectContact (->View). Always needs to return something.
        ViewObjectContact& ViewContact::GetViewObjectContact(ObjectContact& rObjectContact)
        {
            ViewObjectContact* pRetval = 0L;
            const sal_uInt32 nCount(maViewObjectContactVector.size());

            // first search if there exists a VOC for the given OC
            for(sal_uInt32 a(0); !pRetval && a < nCount; a++)
            {
                ViewObjectContact* pCandidate = maViewObjectContactVector[a];
                DBG_ASSERT(pCandidate, "Corrupted ViewObjectContactList (!)");

                if(&(pCandidate->GetObjectContact()) == &rObjectContact)
                {
                    pRetval = pCandidate;
                }
            }

            if(!pRetval)
            {
                // create a new one. It's inserted to the local list from the
                // VieObjectContact constructor via AddViewObjectContact()
                pRetval = &CreateObjectSpecificViewObjectContact(rObjectContact);
            }

            return *pRetval;
        }

        // A new ViewObjectContact was created and shall be remembered.
        void ViewContact::AddViewObjectContact(ViewObjectContact& rVOContact)
        {
            maViewObjectContactVector.push_back(&rVOContact);

            if(1L == maViewObjectContactVector.size())
            {
                StartGettingViewed();
            }
        }

        // A ViewObjectContact was deleted and shall be forgotten.
        void ViewContact::RemoveViewObjectContact(ViewObjectContact& rVOContact)
        {
            std::vector< ViewObjectContact* >::iterator aFindResult = std::find(maViewObjectContactVector.begin(), maViewObjectContactVector.end(), &rVOContact);

            if(aFindResult != maViewObjectContactVector.end())
            {
                maViewObjectContactVector.erase(aFindResult);

                if(maViewObjectContactVector.empty())
                {
                    // This may need to get asynchron later since it eventually triggers
                    // deletes of OCs where the VOC is still added.
                    StopGettingViewed();
                }
            }
        }

        // Test if this ViewContact has ViewObjectContacts at all. This can
        // be used to test if this ViewContact is visualized ATM or not
        bool ViewContact::HasViewObjectContacts(bool bExcludePreviews) const
        {
            const sal_uInt32 nCount(maViewObjectContactVector.size());

            if(bExcludePreviews)
            {
                for(sal_uInt32 a(0); a < nCount; a++)
                {
                    if(!maViewObjectContactVector[a]->GetObjectContact().IsPreviewRenderer())
                    {
                        return true;
                    }
                }

                return false;
            }
            else
            {
                return (0L != nCount);
            }
        }

        // Test if this ViewContact has ViewObjectContacts at all. This can
        // be used to test if this ViewContact is visualized ATM or not
        bool ViewContact::isAnimatedInAnyViewObjectContact() const
        {
            const sal_uInt32 nCount(maViewObjectContactVector.size());

            for(sal_uInt32 a(0); a < nCount; a++)
            {
                if(maViewObjectContactVector[a]->isAnimated())
                {
                    return true;
                }
            }

            return false;
        }

        // Access to possible sub-hierarchy and parent. GetObjectCount() default is 0L
        // and GetViewContact default pops up an assert since it's an error if
        // GetObjectCount has a result != 0 and it's not overloaded.
        sal_uInt32 ViewContact::GetObjectCount() const
        {
            // no sub-objects
            return 0;
        }

        ViewContact& ViewContact::GetViewContact(sal_uInt32 /*nIndex*/) const
        {
            // This is the default implementation; call would be an error
            OSL_FAIL("ViewContact::GetViewContact: This call needs to be overloaded when GetObjectCount() can return results != 0 (!)");
            return (ViewContact&)(*this);
        }

        ViewContact* ViewContact::GetParentContact() const
        {
            // default has no parent
            return 0;
        }

        void ViewContact::ActionChildInserted(ViewContact& rChild)
        {
            // propagate change to all exsisting visualisations which
            // will force a VOC for the new child and invalidate it's range
            const sal_uInt32 nCount(maViewObjectContactVector.size());

            for(sal_uInt32 a(0); a < nCount; a++)
            {
                ViewObjectContact* pCandidate = maViewObjectContactVector[a];
                DBG_ASSERT(pCandidate, "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");

                // take action at all VOCs. At the VOCs ObjectContact the initial
                // rectangle will be invalidated at the associated OutputDevice.
                pCandidate->ActionChildInserted(rChild);
            }
        }

        // React on changes of the object of this ViewContact
        void ViewContact::ActionChanged()
        {
            // propagate change to all existing VOCs. This will invalidate
            // all drawn visualisations in all known views
            const sal_uInt32 nCount(maViewObjectContactVector.size());

            for(sal_uInt32 a(0); a < nCount; a++)
            {
                ViewObjectContact* pCandidate = maViewObjectContactVector[a];
                DBG_ASSERT(pCandidate, "ViewContact::GetViewObjectContact() invalid ViewObjectContactList (!)");

                pCandidate->ActionChanged();
            }
        }

        // access to SdrObject and/or SdrPage. May return 0L like the default
        // implementations do. Needs to be overloaded as needed.
        SdrObject* ViewContact::TryToGetSdrObject() const
        {
            return 0L;
        }

        SdrPage* ViewContact::TryToGetSdrPage() const
        {
            return 0L;
        }

        //////////////////////////////////////////////////////////////////////////////
        // primitive stuff

        drawinglayer::primitive2d::Primitive2DSequence ViewContact::createViewIndependentPrimitive2DSequence() const
        {
            // This is the default implementation and should never be called (see header). If this is called,
            // someone implemented a ViewContact (VC) visualisation object without defining the visualisation by
            // providing a seqence of primitives -> which cannot be correct.
            // Since we have no access to any known model data here, the default implementation creates a yellow placeholder
            // hairline polygon with a default size of (1000, 1000, 5000, 3000)
            OSL_FAIL("ViewContact::createViewIndependentPrimitive2DSequence(): Never call the fallback base implementation, this is always an error (!)");
            const basegfx::B2DPolygon aOutline(basegfx::tools::createPolygonFromRect(basegfx::B2DRange(1000.0, 1000.0, 5000.0, 3000.0)));
            const basegfx::BColor aYellow(1.0, 1.0, 0.0);
            const drawinglayer::primitive2d::Primitive2DReference xReference(
                new drawinglayer::primitive2d::PolygonHairlinePrimitive2D(aOutline, aYellow));

            return drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1);
        }

        drawinglayer::primitive2d::Primitive2DSequence ViewContact::getViewIndependentPrimitive2DSequence() const
        {
            // local up-to-date checks. Create new list and compare.
            const drawinglayer::primitive2d::Primitive2DSequence xNew(createViewIndependentPrimitive2DSequence());

            if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxViewIndependentPrimitive2DSequence, xNew))
            {
                // has changed, copy content
                const_cast< ViewContact* >(this)->mxViewIndependentPrimitive2DSequence = xNew;
            }

            // return current Primitive2DSequence
            return mxViewIndependentPrimitive2DSequence;
        }

        // add Gluepoints (if available)
        drawinglayer::primitive2d::Primitive2DSequence ViewContact::createGluePointPrimitive2DSequence() const
        {
            // default returns empty reference
            return drawinglayer::primitive2d::Primitive2DSequence();
        }

        void ViewContact::flushViewObjectContacts(bool bWithHierarchy)
        {
            if(bWithHierarchy)
            {
                // flush DrawingLayer hierarchy
                const sal_uInt32 nCount(GetObjectCount());

                for(sal_uInt32 a(0); a < nCount; a++)
                {
                    ViewContact& rChild = GetViewContact(a);
                    rChild.flushViewObjectContacts(bWithHierarchy);
                }
            }

            // delete local VOCs
            deleteAllVOCs();
        }
    } // end of namespace contact
} // end of namespace sdr

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