1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
21 #include <string_view>
22 #include <config_folders.h>
24 #include <swtypes.hxx>
25 #include <labelcfg.hxx>
26 #include <rtl/bootstrap.hxx>
27 #include <tools/UnitConversion.hxx>
28 #include <unotools/configpaths.hxx>
29 #include <xmlreader/xmlreader.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <osl/diagnose.h>
32 #include <o3tl/string_view.hxx>
34 #include <com/sun/star/beans/PropertyValue.hpp>
37 using namespace ::com::sun::star::uno
;
38 using namespace ::com::sun::star::beans
;
40 static void lcl_assertEndingItem(xmlreader::XmlReader
& reader
)
44 xmlreader::XmlReader::Result res
;
45 res
= reader
.nextItem(xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
46 assert(res
== xmlreader::XmlReader::Result::End
);
50 static OUString
lcl_getValue(xmlreader::XmlReader
& reader
,
51 const xmlreader::Span
& span
)
55 xmlreader::XmlReader::Result res
;
56 res
= reader
.nextItem(xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
57 assert(res
== xmlreader::XmlReader::Result::Begin
&& name
== span
);
58 res
= reader
.nextItem(xmlreader::XmlReader::Text::Raw
, &name
, &nsId
);
59 assert(res
== xmlreader::XmlReader::Result::Text
);
60 (void) res
; (void) span
;
61 OUString sTmp
= name
.convertFromUtf8();
62 lcl_assertEndingItem(reader
);
66 static Sequence
<OUString
> lcl_CreatePropertyNames(const OUString
& rPrefix
)
68 return { OUString::Concat(rPrefix
) + "Name", OUString::Concat(rPrefix
) + "Measure" };
71 SwLabelConfig::SwLabelConfig() :
72 ConfigItem("Office.Labels/Manufacturer")
74 OUString
uri("$BRAND_BASE_DIR/" LIBO_SHARE_FOLDER
"/labels/labels.xml");
75 rtl::Bootstrap::expandMacros(uri
);
76 xmlreader::XmlReader
reader(uri
);
79 xmlreader::XmlReader::Result res
;
80 OUString sManufacturer
;
84 // fill m_aLabels and m_aManufacturers with the predefined labels
85 res
= reader
.nextItem(
86 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
88 res
== xmlreader::XmlReader::Result::Begin
89 && name
== "manufacturers");
90 res
= reader
.nextItem(
91 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
92 while (res
!= xmlreader::XmlReader::Result::End
)
94 // Opening manufacturer
96 res
== xmlreader::XmlReader::Result::Begin
97 && name
== "manufacturer");
99 (void)reader
.nextAttribute(&nsId
, &name
);
101 nsId
== xmlreader::XmlReader::NAMESPACE_NONE
103 sManufacturer
= reader
.getAttributeValue(false).convertFromUtf8();
106 // Opening label or ending manufacturer
107 res
= reader
.nextItem(
108 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
109 if (res
== xmlreader::XmlReader::Result::End
)
112 res
== xmlreader::XmlReader::Result::Begin
115 sName
= lcl_getValue(reader
, xmlreader::Span("name"));
117 sMeasure
= lcl_getValue(reader
, xmlreader::Span("measure"));
119 lcl_assertEndingItem(reader
);
120 if ( m_aLabels
.find( sManufacturer
) == m_aLabels
.end() )
121 m_aManufacturers
.push_back( sManufacturer
);
122 m_aLabels
[sManufacturer
][sName
].m_aMeasure
= sMeasure
;
123 m_aLabels
[sManufacturer
][sName
].m_bPredefined
= true;
125 // Get next manufacturer or end
126 res
= reader
.nextItem(
127 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
129 res
= reader
.nextItem(
130 xmlreader::XmlReader::Text::NONE
, &name
, &nsId
);
131 assert(res
== xmlreader::XmlReader::Result::Done
);
133 // add to m_aLabels and m_aManufacturers the custom labels
134 const Sequence
<OUString
>& rMan
= GetNodeNames( OUString() );
135 for ( const OUString
& rManufacturer
: rMan
)
137 const Sequence
<OUString
> aLabels
= GetNodeNames( rManufacturer
);
138 for( const OUString
& rLabel
: aLabels
)
140 OUString sPrefix
= rManufacturer
+ "/" + rLabel
+ "/";
141 Sequence
<OUString
> aPropNames
= lcl_CreatePropertyNames( sPrefix
);
142 Sequence
<Any
> aValues
= GetProperties( aPropNames
);
143 const Any
* pValues
= aValues
.getConstArray();
144 if (aValues
.getLength() >= 1)
145 if(pValues
[0].hasValue())
146 pValues
[0] >>= sName
;
147 if (aValues
.getLength() >= 2)
148 if(pValues
[1].hasValue())
149 pValues
[1] >>= sMeasure
;
150 if ( m_aLabels
.find( rManufacturer
) == m_aLabels
.end() )
151 m_aManufacturers
.push_back( rManufacturer
);
152 m_aLabels
[rManufacturer
][sName
].m_aMeasure
= sMeasure
;
153 m_aLabels
[rManufacturer
][sName
].m_bPredefined
= false;
158 SwLabelConfig::~SwLabelConfig()
162 // the config item is not writable ?:
163 void SwLabelConfig::ImplCommit() {}
165 void SwLabelConfig::Notify( const css::uno::Sequence
< OUString
>& ) {}
167 static std::unique_ptr
<SwLabRec
> lcl_CreateSwLabRec(const OUString
& rType
, std::u16string_view rMeasure
, const OUString
& rManufacturer
)
169 std::unique_ptr
<SwLabRec
> pNewRec(new SwLabRec
);
170 pNewRec
->m_aMake
= rManufacturer
;
171 pNewRec
->m_nPWidth
= 0;
172 pNewRec
->m_nPHeight
= 0;
173 pNewRec
->m_aType
= rType
;
174 //all values are contained as colon-separated 1/100 mm values
175 //except for the continuous flag ('C'/'S') and nCols, nRows (sal_Int32)
177 sal_Int32 nIdx
{rMeasure
.empty() ? -1 : 0};
180 const std::u16string_view
sToken(o3tl::getToken(rMeasure
, 0, ';', nIdx
));
181 int nVal
= o3tl::toInt32(sToken
);
184 case 0 : pNewRec
->m_bCont
= sToken
[0] == 'C'; break;
185 case 1 : pNewRec
->m_nHDist
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
186 case 2 : pNewRec
->m_nVDist
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
187 case 3 : pNewRec
->m_nWidth
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
188 case 4 : pNewRec
->m_nHeight
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
189 case 5 : pNewRec
->m_nLeft
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
190 case 6 : pNewRec
->m_nUpper
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
191 case 7 : pNewRec
->m_nCols
= nVal
; break;
192 case 8 : pNewRec
->m_nRows
= nVal
; break;
193 case 9 : pNewRec
->m_nPWidth
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
194 case 10 : pNewRec
->m_nPHeight
= o3tl::toTwips(nVal
, o3tl::Length::mm100
); break;
197 // lines added for compatibility with custom label definitions saved before patch fdo#44516
198 if (pNewRec
->m_nPWidth
== 0 || pNewRec
->m_nPHeight
== 0)
200 // old style definition (no paper dimensions), calculate probable values
201 pNewRec
->m_nPWidth
= 2 * pNewRec
->m_nLeft
+ (pNewRec
->m_nCols
- 1) * pNewRec
->m_nHDist
+ pNewRec
->m_nWidth
;
202 pNewRec
->m_nPHeight
= ( pNewRec
->m_bCont
? pNewRec
->m_nRows
* pNewRec
->m_nVDist
: 2 * pNewRec
->m_nUpper
+ (pNewRec
->m_nRows
- 1) * pNewRec
->m_nVDist
+ pNewRec
->m_nHeight
);
207 static Sequence
<PropertyValue
> lcl_CreateProperties(
208 Sequence
<OUString
> const & rPropNames
, OUString
& rMeasure
, const SwLabRec
& rRec
)
210 const OUString
* pNames
= rPropNames
.getConstArray();
211 Sequence
<PropertyValue
> aRet(rPropNames
.getLength());
212 PropertyValue
* pValues
= aRet
.getArray();
213 OUString
sColon(";");
215 for(sal_Int32 nProp
= 0; nProp
< rPropNames
.getLength(); nProp
++)
217 pValues
[nProp
].Name
= pNames
[nProp
];
220 case 0: pValues
[nProp
].Value
<<= rRec
.m_aType
; break;
224 rMeasure
+= rRec
.m_bCont
? std::u16string_view( u
"C" ) : std::u16string_view( u
"S" ); rMeasure
+= sColon
;
225 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nHDist
) ); rMeasure
+= sColon
;
226 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nVDist
) ); rMeasure
+= sColon
;
227 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nWidth
) ); rMeasure
+= sColon
;
228 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nHeight
) ); rMeasure
+= sColon
;
229 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nLeft
) ); rMeasure
+= sColon
;
230 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nUpper
) ); rMeasure
+= sColon
;
231 rMeasure
+= OUString::number( rRec
.m_nCols
); rMeasure
+= sColon
;
232 rMeasure
+= OUString::number( rRec
.m_nRows
); rMeasure
+= sColon
;
233 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nPWidth
) ); rMeasure
+= sColon
;
234 rMeasure
+= OUString::number( convertTwipToMm100( rRec
.m_nPHeight
) );
235 pValues
[nProp
].Value
<<= rMeasure
;
243 // function fills SwLabDlg with label definitions for manufacturer rManufacturer
244 void SwLabelConfig::FillLabels(const OUString
& rManufacturer
, SwLabRecs
& rLabArr
)
246 if (m_aLabels
.find(rManufacturer
) == m_aLabels
.end())
248 for (const auto& rEntry
: m_aLabels
[rManufacturer
])
249 rLabArr
.push_back( lcl_CreateSwLabRec(rEntry
.first
, rEntry
.second
.m_aMeasure
, rManufacturer
) );
252 bool SwLabelConfig::HasLabel(const OUString
& rManufacturer
, const OUString
& rType
)
254 return ( ( m_aLabels
.find(rManufacturer
) != m_aLabels
.end() ) &&
255 ( m_aLabels
[rManufacturer
].find(rType
) != m_aLabels
[rManufacturer
].end() ) );
258 // label is always saved as a custom label
259 // predefined labels can NOT be overwritten by custom labels with same manufacturer/name
260 void SwLabelConfig::SaveLabel( const OUString
& rManufacturer
,
261 const OUString
& rType
, const SwLabRec
& rRec
)
264 bool bManufacturerNodeFound
;
265 if ( m_aLabels
.find( rManufacturer
) == m_aLabels
.end() ||
266 !GetNodeNames( rManufacturer
).hasElements() )
268 bManufacturerNodeFound
= false;
269 // manufacturer node does not exist, add (and also to m_aManufacturers)
270 if ( !AddNode( OUString(), rManufacturer
) )
272 OSL_FAIL("New configuration node could not be created");
275 m_aManufacturers
.push_back( rManufacturer
);
278 bManufacturerNodeFound
= true;
280 if ( !bManufacturerNodeFound
||
281 m_aLabels
[rManufacturer
].find( rType
) == m_aLabels
[rManufacturer
].end() )
283 // type does not yet exist, add to config
284 const Sequence
<OUString
> aLabels
= GetNodeNames( rManufacturer
);
285 sal_Int32 nIndex
= aLabels
.getLength();
286 OUString
sPrefix( "Label" );
287 sFoundNode
= sPrefix
+ OUString::number( nIndex
);
288 while ( comphelper::findValue(aLabels
, sFoundNode
) != -1 )
290 sFoundNode
= sPrefix
+ OUString::number(nIndex
++);
295 // get the appropriate node
296 OUString
sManufacturer( wrapConfigurationElementName( rManufacturer
) );
297 const Sequence
<OUString
> aLabels
= GetNodeNames( sManufacturer
);
298 for (const OUString
& rLabel
: aLabels
)
300 OUString sPrefix
= sManufacturer
+ "/" + rLabel
+ "/";
301 Sequence
<OUString
> aProperties
{ sPrefix
};
302 aProperties
.getArray()[0] += "Name";
303 Sequence
<Any
> aValues
= GetProperties( aProperties
);
304 const Any
* pValues
= aValues
.getConstArray();
305 if ( pValues
[0].hasValue() )
318 OUString sPrefix
= wrapConfigurationElementName( rManufacturer
) +
319 "/" + sFoundNode
+ "/";
320 Sequence
<OUString
> aPropNames
= lcl_CreatePropertyNames( sPrefix
);
322 Sequence
<PropertyValue
> aPropValues
= lcl_CreateProperties( aPropNames
, sMeasure
, rRec
);
323 SetSetProperties( wrapConfigurationElementName( rManufacturer
), aPropValues
);
326 m_aLabels
[rManufacturer
][rType
].m_aMeasure
= sMeasure
;
327 m_aLabels
[rManufacturer
][rType
].m_bPredefined
= false;
330 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */