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 <vector>
21 
22 #include <tools/solar.h>
23 #include <o3tl/sorted_vector.hxx>
24 #include <com/sun/star/ucb/XAnyCompareFactory.hpp>
25 #include <com/sun/star/container/XNamed.hpp>
26 #include <com/sun/star/container/XIndexReplace.hpp>
27 #include <rtl/ustrbuf.hxx>
28 #include <sal/log.hxx>
29 #include <xmloff/xmlnume.hxx>
30 #include <xmloff/XMLTextListAutoStylePool.hxx>
31 #include <xmloff/xmlexp.hxx>
32 
33 
34 using namespace ::com::sun::star;
35 using namespace ::com::sun::star::uno;
36 using namespace ::com::sun::star::beans;
37 using namespace ::com::sun::star::container;
38 using namespace ::com::sun::star::style;
39 
40 
41 class XMLTextListAutoStylePoolEntry_Impl
42 {
43     OUString    sName;
44     OUString    sInternalName;
45     Reference < XIndexReplace > xNumRules;
46     sal_uInt32 const  nPos;
47     bool    bIsNamed;
48 
49 
50 public:
51 
52     XMLTextListAutoStylePoolEntry_Impl(
53             sal_uInt32 nPos,
54             const Reference < XIndexReplace > & rNumRules,
55             XMLTextListAutoStylePoolNames_Impl& rNames,
56             const OUString& rPrefix,
57             sal_uInt32& rName );
58 
XMLTextListAutoStylePoolEntry_Impl(const Reference<XIndexReplace> & rNumRules)59     explicit XMLTextListAutoStylePoolEntry_Impl(
60             const Reference < XIndexReplace > & rNumRules ) :
61         xNumRules( rNumRules ),
62         nPos( 0 ),
63         bIsNamed( false )
64     {
65         Reference < XNamed > xNamed( xNumRules, UNO_QUERY );
66         if( xNamed.is() )
67         {
68             sInternalName = xNamed->getName();
69             bIsNamed = true;
70         }
71     }
72 
XMLTextListAutoStylePoolEntry_Impl(const OUString & rInternalName)73     explicit XMLTextListAutoStylePoolEntry_Impl(
74             const OUString& rInternalName ) :
75         sInternalName( rInternalName ),
76         nPos( 0 ),
77         bIsNamed( true )
78     {
79     }
80 
GetName() const81     const OUString& GetName() const { return sName; }
GetInternalName() const82     const OUString& GetInternalName() const { return sInternalName; }
GetNumRules() const83     const Reference < XIndexReplace > & GetNumRules() const { return xNumRules; }
GetPos() const84     sal_uInt32 GetPos() const { return nPos; }
IsNamed() const85     bool IsNamed() const { return bIsNamed; }
86 };
87 
XMLTextListAutoStylePoolEntry_Impl(sal_uInt32 nP,const Reference<XIndexReplace> & rNumRules,XMLTextListAutoStylePoolNames_Impl & rNames,const OUString & rPrefix,sal_uInt32 & rName)88 XMLTextListAutoStylePoolEntry_Impl::XMLTextListAutoStylePoolEntry_Impl(
89         sal_uInt32 nP,
90         const Reference < XIndexReplace > & rNumRules,
91         XMLTextListAutoStylePoolNames_Impl& rNames,
92         const OUString& rPrefix,
93         sal_uInt32& rName ) :
94     xNumRules( rNumRules ),
95     nPos( nP ),
96     bIsNamed( false )
97 {
98     Reference < XNamed > xNamed( xNumRules, UNO_QUERY );
99     if( xNamed.is() )
100     {
101         sInternalName = xNamed->getName();
102         bIsNamed = true;
103     }
104 
105     // create a name that hasn't been used before. The created name has not
106     // to be added to the array, because it will never tried again
107     OUStringBuffer sBuffer( 7 );
108     do
109     {
110         rName++;
111         sBuffer.append( rPrefix );
112         sBuffer.append( static_cast<sal_Int32>(rName) );
113         sName = sBuffer.makeStringAndClear();
114     }
115     while (rNames.find(sName) != rNames.end());
116 }
117 
118 struct XMLTextListAutoStylePoolEntryCmp_Impl
119 {
operator ()XMLTextListAutoStylePoolEntryCmp_Impl120     bool operator()(
121             std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> const& r1,
122             std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> const& r2 ) const
123     {
124         if( r1->IsNamed() )
125         {
126             if( r2->IsNamed() )
127                 return r1->GetInternalName().compareTo( r2->GetInternalName() ) < 0;
128             else
129                 return true;
130         }
131         else
132         {
133             if( r2->IsNamed() )
134                 return false;
135             else
136                 return r1->GetNumRules().get() < r2->GetNumRules().get();
137         }
138     }
139 };
140 class XMLTextListAutoStylePool_Impl : public o3tl::sorted_vector<std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl>, XMLTextListAutoStylePoolEntryCmp_Impl> {};
141 
XMLTextListAutoStylePool(SvXMLExport & rExp)142 XMLTextListAutoStylePool::XMLTextListAutoStylePool( SvXMLExport& rExp ) :
143     rExport( rExp ),
144     sPrefix( "L" ),
145     pPool( new XMLTextListAutoStylePool_Impl ),
146     nName( 0 )
147 {
148     Reference<ucb::XAnyCompareFactory> xCompareFac( rExp.GetModel(), uno::UNO_QUERY );
149     if( xCompareFac.is() )
150         mxNumRuleCompare = xCompareFac->createAnyCompareByName( "NumberingRules" );
151     SvXMLExportFlags nExportFlags = rExport.getExportFlags();
152     bool bStylesOnly = (nExportFlags & SvXMLExportFlags::STYLES) && !(nExportFlags & SvXMLExportFlags::CONTENT);
153     if( bStylesOnly )
154         sPrefix = "ML";
155 
156 }
157 
~XMLTextListAutoStylePool()158 XMLTextListAutoStylePool::~XMLTextListAutoStylePool()
159 {
160 }
161 
RegisterName(const OUString & rName)162 void XMLTextListAutoStylePool::RegisterName( const OUString& rName )
163 {
164     m_aNames.insert(rName);
165 }
166 
Find(const XMLTextListAutoStylePoolEntry_Impl * pEntry) const167 sal_uInt32 XMLTextListAutoStylePool::Find( const XMLTextListAutoStylePoolEntry_Impl* pEntry ) const
168 {
169     if( !pEntry->IsNamed() && mxNumRuleCompare.is() )
170     {
171         const sal_uInt32 nCount = pPool->size();
172 
173         uno::Any aAny1, aAny2;
174         aAny1 <<= pEntry->GetNumRules();
175 
176         for( sal_uInt32 nPos = 0; nPos < nCount; nPos++ )
177         {
178             aAny2 <<= (*pPool)[nPos]->GetNumRules();
179 
180             if( mxNumRuleCompare->compare( aAny1, aAny2 ) == 0 )
181                 return nPos;
182         }
183     }
184     else
185     {
186         XMLTextListAutoStylePool_Impl::const_iterator it = pPool->find( pEntry );
187         if( it != pPool->end() )
188             return it - pPool->begin();
189     }
190 
191     return sal_uInt32(-1);
192 }
193 
Add(const Reference<XIndexReplace> & rNumRules)194 OUString XMLTextListAutoStylePool::Add(
195             const Reference < XIndexReplace > & rNumRules )
196 {
197     OUString sName;
198     XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules );
199 
200     sal_uInt32 nPos = Find( &aTmp );
201     if( nPos != sal_uInt32(-1) )
202     {
203         sName = (*pPool)[ nPos ]->GetName();
204     }
205     else
206     {
207         std::unique_ptr<XMLTextListAutoStylePoolEntry_Impl> pEntry(
208             new XMLTextListAutoStylePoolEntry_Impl( pPool->size(),
209                                                rNumRules, m_aNames, sPrefix,
210                                                nName ));
211         sName = pEntry->GetName();
212         pPool->insert( std::move(pEntry) );
213     }
214 
215     return sName;
216 }
217 
Find(const Reference<XIndexReplace> & rNumRules) const218 OUString XMLTextListAutoStylePool::Find(
219             const Reference < XIndexReplace > & rNumRules ) const
220 {
221     OUString sName;
222     XMLTextListAutoStylePoolEntry_Impl aTmp( rNumRules );
223 
224     sal_uInt32 nPos = Find( &aTmp );
225     if( nPos != sal_uInt32(-1) )
226         sName = (*pPool)[ nPos ]->GetName();
227 
228     return sName;
229 }
230 
Find(const OUString & rInternalName) const231 OUString XMLTextListAutoStylePool::Find(
232             const OUString& rInternalName ) const
233 {
234     OUString sName;
235     XMLTextListAutoStylePoolEntry_Impl aTmp( rInternalName );
236     sal_uInt32 nPos = Find( &aTmp );
237     if( nPos != sal_uInt32(-1) )
238         sName = (*pPool)[ nPos ]->GetName();
239 
240     return sName;
241 }
242 
exportXML() const243 void XMLTextListAutoStylePool::exportXML() const
244 {
245     sal_uInt32 nCount = pPool->size();
246     if( !nCount )
247         return;
248 
249     std::vector<XMLTextListAutoStylePoolEntry_Impl*> aExpEntries(nCount);
250 
251     sal_uInt32 i;
252     for( i=0; i < nCount; i++ )
253     {
254         XMLTextListAutoStylePoolEntry_Impl *pEntry = (*pPool)[i].get();
255         SAL_WARN_IF( pEntry->GetPos() >= nCount, "xmloff", "Illegal pos" );
256         aExpEntries[pEntry->GetPos()] = pEntry;
257     }
258 
259     SvxXMLNumRuleExport aNumRuleExp( rExport );
260 
261     for( i=0; i < nCount; i++ )
262     {
263         XMLTextListAutoStylePoolEntry_Impl *pEntry = aExpEntries[i];
264         aNumRuleExp.exportNumberingRule( pEntry->GetName(), false,
265                                          pEntry->GetNumRules() );
266     }
267 }
268 
269 
270 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
271