1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 #include "precompiled_sd.hxx"
29 
30 #include "ConfigurationClassifier.hxx"
31 
32 #include "framework/FrameworkHelper.hxx"
33 
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::uno;
36 using namespace ::com::sun::star::drawing::framework;
37 using ::rtl::OUString;
38 
39 #undef VERBOSE
40 //#define VERBOSE 2
41 
42 
43 namespace sd { namespace framework {
44 
45 ConfigurationClassifier::ConfigurationClassifier (
46     const Reference<XConfiguration>& rxConfiguration1,
47     const Reference<XConfiguration>& rxConfiguration2)
48     : mxConfiguration1(rxConfiguration1),
49       mxConfiguration2(rxConfiguration2),
50       maC1minusC2(),
51       maC2minusC1(),
52       maC1andC2()
53 {
54 }
55 
56 
57 
58 
59 bool ConfigurationClassifier::Partition (void)
60 {
61     maC1minusC2.clear();
62     maC2minusC1.clear();
63     maC1andC2.clear();
64 
65     PartitionResources(
66         mxConfiguration1->getResources(NULL, OUString(), AnchorBindingMode_DIRECT),
67         mxConfiguration2->getResources(NULL, OUString(), AnchorBindingMode_DIRECT));
68 
69     return !maC1minusC2.empty() || !maC2minusC1.empty();
70 }
71 
72 
73 
74 
75 const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC1minusC2 (void) const
76 {
77     return maC1minusC2;
78 }
79 
80 
81 
82 
83 const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC2minusC1 (void) const
84 {
85     return maC2minusC1;
86 }
87 
88 
89 
90 const ConfigurationClassifier::ResourceIdVector& ConfigurationClassifier::GetC1andC2 (void) const
91 {
92     return maC1andC2;
93 }
94 
95 
96 void ConfigurationClassifier::PartitionResources (
97     const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS1,
98     const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS2)
99 {
100     ResourceIdVector aC1minusC2;
101     ResourceIdVector aC2minusC1;
102     ResourceIdVector aC1andC2;
103 
104     // Classify the resources in the configurations that are not bound to
105     // other resources.
106     ClassifyResources(
107         rS1,
108         rS2,
109         aC1minusC2,
110         aC2minusC1,
111         aC1andC2);
112 
113 #if defined VERBOSE && VERBOSE >= 2
114     OSL_TRACE("copying resource ids to C1-C2\r");
115 #endif
116     CopyResources(aC1minusC2, mxConfiguration1, maC1minusC2);
117 #if defined VERBOSE && VERBOSE >= 2
118     OSL_TRACE("copying resource ids to C2-C1\r");
119 #endif
120     CopyResources(aC2minusC1, mxConfiguration2, maC2minusC1);
121 
122     // Process the unique resources that belong to both configurations.
123     ResourceIdVector::const_iterator iResource;
124     for (iResource=aC1andC2.begin(); iResource!=aC1andC2.end(); ++iResource)
125     {
126         maC1andC2.push_back(*iResource);
127         PartitionResources(
128             mxConfiguration1->getResources(*iResource, OUString(), AnchorBindingMode_DIRECT),
129             mxConfiguration2->getResources(*iResource, OUString(), AnchorBindingMode_DIRECT));
130     }
131 }
132 
133 
134 
135 
136 void ConfigurationClassifier::ClassifyResources (
137     const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS1,
138     const ::com::sun::star::uno::Sequence<Reference<XResourceId> >& rS2,
139     ResourceIdVector& rS1minusS2,
140     ResourceIdVector& rS2minusS1,
141     ResourceIdVector& rS1andS2)
142 {
143     // Get arrays from the sequences for faster iteration.
144     const Reference<XResourceId>* aA1 = rS1.getConstArray();
145     const Reference<XResourceId>* aA2 = rS2.getConstArray();
146     sal_Int32 nL1 (rS1.getLength());
147     sal_Int32 nL2 (rS2.getLength());
148 
149     // Find all elements in rS1 and place them in rS1minusS2 or rS1andS2
150     // depending on whether they are in rS2 or not.
151     for (sal_Int32 i=0; i<nL1; ++i)
152     {
153         bool bFound (false);
154         for (sal_Int32 j=0; j<nL2 && !bFound; ++j)
155             if (aA1[i]->getResourceURL().equals(aA2[j]->getResourceURL()))
156                 bFound = true;
157 
158         if (bFound)
159             rS1andS2.push_back(aA1[i]);
160         else
161             rS1minusS2.push_back(aA1[i]);
162     }
163 
164     // Find all elements in rS2 that are not in rS1.  The elements that are
165     // in both rS1 and rS2 have been handled above and are therefore ignored
166     // here.
167     for (sal_Int32 j=0; j<nL2; ++j)
168     {
169         bool bFound (false);
170         for (sal_Int32 i=0; i<nL1 && !bFound; ++i)
171             if (aA2[j]->getResourceURL().equals(aA1[i]->getResourceURL()))
172                 bFound = true;
173 
174         if ( ! bFound)
175             rS2minusS1.push_back(aA2[j]);
176     }
177 }
178 
179 
180 
181 
182 void ConfigurationClassifier::CopyResources (
183     const ResourceIdVector& rSource,
184     const Reference<XConfiguration>& rxConfiguration,
185     ResourceIdVector& rTarget)
186 {
187     // Copy all resources bound to the ones in aC1minusC2Unique to rC1minusC2.
188     ResourceIdVector::const_iterator iResource (rSource.begin());
189     ResourceIdVector::const_iterator iEnd(rSource.end());
190     for ( ; iResource!=iEnd; ++iResource)
191     {
192         const Sequence<Reference<XResourceId> > aBoundResources (
193             rxConfiguration->getResources(
194                 *iResource,
195                 OUString(),
196                 AnchorBindingMode_INDIRECT));
197         const sal_Int32 nL (aBoundResources.getLength());
198 
199         rTarget.reserve(rTarget.size() + 1 + nL);
200         rTarget.push_back(*iResource);
201 
202 #if defined VERBOSE && VERBOSE >= 2
203         OSL_TRACE("    copying %s\r",
204             OUStringToOString(FrameworkHelper::ResourceIdToString(*iResource),
205                 RTL_TEXTENCODING_UTF8).getStr());
206 #endif
207 
208         const Reference<XResourceId>* aA = aBoundResources.getConstArray();
209         for (sal_Int32 i=0; i<nL; ++i)
210         {
211             rTarget.push_back(aA[i]);
212 #if defined VERBOSE && VERBOSE >= 2
213             OSL_TRACE("    copying %s\r",
214                 OUStringToOString(FrameworkHelper::ResourceIdToString(aA[i]),
215                     RTL_TEXTENCODING_UTF8).getStr());
216 #endif
217         }
218     }
219 }
220 
221 
222 void ConfigurationClassifier::TraceResourceIdVector (
223     const sal_Char* pMessage,
224     const ResourceIdVector& rResources) const
225 {
226 
227     OSL_TRACE(pMessage);
228     ResourceIdVector::const_iterator iResource;
229     for (iResource=rResources.begin(); iResource!=rResources.end(); ++iResource)
230     {
231         OUString sResource (FrameworkHelper::ResourceIdToString(*iResource));
232         OSL_TRACE("    %s\r",
233             OUStringToOString(sResource, RTL_TEXTENCODING_UTF8).getStr());
234     }
235 }
236 
237 
238 } } // end of namespace sd::framework
239