xref: /core/sfx2/source/dialog/dinfdlg.cxx (revision b583b3de795854141a754a632aa34eeb0974a55f)
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 <svl/eitem.hxx>
21 #include <tools/datetime.hxx>
22 #include <tools/duration.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/urlobj.hxx>
25 #include <utility>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <vcl/weldutils.hxx>
29 #include <unotools/datetime.hxx>
30 #include <unotools/localedatawrapper.hxx>
31 #include <unotools/cmdoptions.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/propertyvalue.hxx>
34 #include <comphelper/stl_types.hxx>
35 #include <comphelper/xmlsechelper.hxx>
36 #include <unotools/useroptions.hxx>
37 #include <svtools/ctrlbox.hxx>
38 #include <svtools/imagemgr.hxx>
39 #include <sal/log.hxx>
40 #include <osl/diagnose.h>
41 #include <osl/file.hxx>
42 #include <comphelper/lok.hxx>
43 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
44 #include <tools/json_writer.hxx>
45 
46 #include <memory>
47 
48 #include <comphelper/sequence.hxx>
49 #include <comphelper/string.hxx>
50 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
51 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
52 #include <unotools/syslocale.hxx>
53 #include <rtl/math.hxx>
54 #include <com/sun/star/beans/PropertyAttribute.hpp>
55 #include <com/sun/star/beans/XPropertyContainer.hpp>
56 #include <com/sun/star/beans/XPropertySet.hpp>
57 #include <com/sun/star/util/DateTime.hpp>
58 #include <com/sun/star/util/Date.hpp>
59 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
60 #include <com/sun/star/util/DateWithTimezone.hpp>
61 #include <com/sun/star/util/Duration.hpp>
62 #include <com/sun/star/document/XDocumentProperties2.hpp>
63 #include <com/sun/star/document/CmisProperty.hpp>
64 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
65 
66 #include <vcl/timer.hxx>
67 #include <vcl/settings.hxx>
68 #include <sfx2/sfxresid.hxx>
69 #include <sfx2/frame.hxx>
70 #include <sfx2/filedlghelper.hxx>
71 #include <sfx2/dinfdlg.hxx>
72 #include <sfx2/sfxsids.hrc>
73 #include <helper.hxx>
74 #include <sfx2/objsh.hxx>
75 #include <sfx2/docfile.hxx>
76 #include <vcl/abstdlg.hxx>
77 #include <sfx2/viewsh.hxx>
78 
79 #include <documentfontsdialog.hxx>
80 #include <dinfdlg.hrc>
81 #include <sfx2/strings.hrc>
82 #include <strings.hxx>
83 #include <comphelper/diagnose_ex.hxx>
84 #include "securitypage.hxx"
85 
86 #include <algorithm>
87 
88 #include <vcl/tabs.hrc>
89 
90 using namespace ::com::sun::star;
91 using namespace ::com::sun::star::uno;
92 
93 struct CustomProperty
94 {
95     OUString         m_sName;
96     css::uno::Any    m_aValue;
97 
CustomPropertyCustomProperty98     CustomProperty( OUString sName, css::uno::Any aValue ) :
99         m_sName(std::move( sName )), m_aValue(std::move( aValue )) {}
100 
operator ==CustomProperty101     bool operator==(const CustomProperty& rProp) const
102     {
103         return m_sName == rProp.m_sName && m_aValue == rProp.m_aValue;
104     }
105 };
106 
CreateDefault()107 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
108 
109 namespace {
110 
CreateSizeText(sal_Int64 nSize)111 OUString CreateSizeText( sal_Int64 nSize )
112 {
113     OUString aUnitStr = " " + SfxResId(STR_BYTES);
114     sal_Int64 nSize1 = nSize;
115     sal_Int64 nSize2 = nSize1;
116     sal_Int64 nMega = 1024 * 1024;
117     sal_Int64 nGiga = nMega * 1024;
118     double fSize = nSize;
119     int nDec = 0;
120 
121     if ( nSize1 >= 10000 && nSize1 < nMega )
122     {
123         nSize1 /= 1024;
124         aUnitStr = " " + SfxResId(STR_KB);
125         fSize /= 1024;
126         nDec = 0;
127     }
128     else if ( nSize1 >= nMega && nSize1 < nGiga )
129     {
130         nSize1 /= nMega;
131         aUnitStr = " " + SfxResId(STR_MB);
132         fSize /= nMega;
133         nDec = 2;
134     }
135     else if ( nSize1 >= nGiga )
136     {
137         nSize1 /= nGiga;
138         aUnitStr = " " + SfxResId(STR_GB);
139         fSize /= nGiga;
140         nDec = 3;
141     }
142     const SvtSysLocale aSysLocale;
143     const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
144     OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
145     if ( nSize1 < nSize2 )
146     {
147         aSizeStr = ::rtl::math::doubleToUString( fSize,
148                 rtl_math_StringFormat_F, nDec,
149                 rLocaleWrapper.getNumDecimalSep()[0] )
150                  + aUnitStr
151                  + " ("
152                  + rLocaleWrapper.getNum( nSize2, 0 )
153                  + " "
154                  + SfxResId(STR_BYTES)
155                  + ")";
156     }
157     return aSizeStr;
158 }
159 
ConvertDateTime_Impl(std::u16string_view rName,const util::DateTime & uDT,const LocaleDataWrapper & rWrapper)160 OUString ConvertDateTime_Impl( std::u16string_view rName,
161     const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
162 {
163      Date aD(uDT);
164      tools::Time aT(uDT);
165      static constexpr OUString aDelim( u", "_ustr );
166      OUString aStr = rWrapper.getDate( aD )
167                    + aDelim
168                    + rWrapper.getTime( aT );
169      std::u16string_view aAuthor = comphelper::string::stripStart(rName, ' ');
170      if (!aAuthor.empty())
171      {
172         aStr += aDelim + aAuthor;
173      }
174      return aStr;
175 }
176 
177 }
178 
179 
SfxDocumentInfoItem()180 SfxDocumentInfoItem::SfxDocumentInfoItem()
181     : m_AutoloadDelay(0)
182     , m_isAutoloadEnabled(false)
183     , m_EditingCycles(0)
184     , m_EditingDuration(0)
185     , m_nFileSize(-1)
186     , m_bHasTemplate( true )
187     , m_bDeleteUserData( false )
188     , m_bUseUserData( true )
189     , m_bUseThumbnailSave( true )
190 {
191 }
192 
SfxDocumentInfoItem(const OUString & rFile,const uno::Reference<document::XDocumentProperties> & i_xDocProps,const uno::Sequence<document::CmisProperty> & i_cmisProps,bool bIs,bool _bIs,sal_Int64 _nFileSize)193 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
194         const uno::Reference<document::XDocumentProperties>& i_xDocProps,
195         const uno::Sequence<document::CmisProperty>& i_cmisProps,
196         bool bIs, bool _bIs, sal_Int64 _nFileSize )
197     : SfxStringItem( SID_DOCINFO, rFile )
198     , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
199     , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
200     , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
201     , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
202     , m_TemplateName( i_xDocProps->getTemplateName() )
203     , m_Author( i_xDocProps->getAuthor() )
204     , m_CreationDate( i_xDocProps->getCreationDate() )
205     , m_ModifiedBy( i_xDocProps->getModifiedBy() )
206     , m_ModificationDate( i_xDocProps->getModificationDate() )
207     , m_PrintedBy( i_xDocProps->getPrintedBy() )
208     , m_PrintDate( i_xDocProps->getPrintDate() )
209     , m_EditingCycles( i_xDocProps->getEditingCycles() )
210     , m_EditingDuration( i_xDocProps->getEditingDuration() )
211     , m_Description( i_xDocProps->getDescription() )
212     , m_Keywords( ::comphelper::string::convertCommaSeparated(
213                     i_xDocProps->getKeywords()) )
214     , m_Subject( i_xDocProps->getSubject() )
215     , m_Title( i_xDocProps->getTitle() )
216     , m_nFileSize( _nFileSize )
217     , m_bHasTemplate( true )
218     , m_bDeleteUserData( false )
219     , m_bUseUserData( bIs )
220     , m_bUseThumbnailSave( _bIs )
221 {
222     Reference< document::XDocumentProperties2 > xDocProps2(i_xDocProps, UNO_QUERY);
223     m_Contributor = ::comphelper::string::convertCommaSeparated(xDocProps2->getContributor());
224     m_Coverage = xDocProps2->getCoverage();
225     m_Identifier = xDocProps2->getIdentifier();
226     m_Publisher = ::comphelper::string::convertCommaSeparated(xDocProps2->getPublisher());
227     m_Relation = ::comphelper::string::convertCommaSeparated(xDocProps2->getRelation());
228     m_Rights = xDocProps2->getRights();
229     m_Source = xDocProps2->getSource();
230     m_Type = xDocProps2->getType();
231 
232     try
233     {
234         Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
235         if ( xContainer.is() )
236         {
237             Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
238             const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
239             for ( const beans::Property& rProp : lProps )
240             {
241                 // "fix" property? => not a custom property => ignore it!
242                 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
243                 {
244                     SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
245                     continue;
246                 }
247 
248                 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
249                 AddCustomProperty( rProp.Name, aValue );
250             }
251         }
252 
253         // get CMIS properties
254         m_aCmisProperties = i_cmisProps;
255     }
256     catch ( Exception& ) {}
257 }
258 
259 
SfxDocumentInfoItem(const SfxDocumentInfoItem & rItem)260 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
261     : SfxStringItem( rItem )
262     , m_AutoloadDelay( rItem.getAutoloadDelay() )
263     , m_AutoloadURL( rItem.getAutoloadURL() )
264     , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
265     , m_DefaultTarget( rItem.getDefaultTarget() )
266     , m_TemplateName( rItem.getTemplateName() )
267     , m_Author( rItem.getAuthor() )
268     , m_CreationDate( rItem.getCreationDate() )
269     , m_ModifiedBy( rItem.getModifiedBy() )
270     , m_ModificationDate( rItem.getModificationDate() )
271     , m_PrintedBy( rItem.getPrintedBy() )
272     , m_PrintDate( rItem.getPrintDate() )
273     , m_EditingCycles( rItem.getEditingCycles() )
274     , m_EditingDuration( rItem.getEditingDuration() )
275     , m_Description( rItem.getDescription() )
276     , m_Keywords( rItem.getKeywords() )
277     , m_Contributor(rItem.getContributor())
278     , m_Coverage(rItem.getCoverage())
279     , m_Identifier(rItem.getIdentifier())
280     , m_Publisher(rItem.getPublisher())
281     , m_Relation(rItem.getRelation())
282     , m_Rights(rItem.getRights())
283     , m_Source(rItem.getSource())
284     , m_Type(rItem.getType())
285     , m_Subject( rItem.getSubject() )
286     , m_Title( rItem.getTitle() )
287     , m_nFileSize ( rItem.m_nFileSize )
288     , m_bHasTemplate( rItem.m_bHasTemplate )
289     , m_bDeleteUserData( rItem.m_bDeleteUserData )
290     , m_bUseUserData( rItem.m_bUseUserData )
291     , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
292 {
293     for (auto const & pOtherProp : rItem.m_aCustomProperties)
294     {
295         AddCustomProperty( pOtherProp->m_sName, pOtherProp->m_aValue );
296     }
297 
298     m_aCmisProperties = rItem.m_aCmisProperties;
299 }
300 
~SfxDocumentInfoItem()301 SfxDocumentInfoItem::~SfxDocumentInfoItem()
302 {
303     ClearCustomProperties();
304 }
305 
Clone(SfxItemPool *) const306 SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
307 {
308     return new SfxDocumentInfoItem( *this );
309 }
310 
operator ==(const SfxPoolItem & rItem) const311 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
312 {
313     if (!SfxStringItem::operator==(rItem))
314         return false;
315     const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
316 
317     return
318          m_AutoloadDelay        == rInfoItem.m_AutoloadDelay     &&
319          m_AutoloadURL          == rInfoItem.m_AutoloadURL       &&
320          m_isAutoloadEnabled    == rInfoItem.m_isAutoloadEnabled &&
321          m_DefaultTarget        == rInfoItem.m_DefaultTarget     &&
322          m_Author               == rInfoItem.m_Author            &&
323          m_CreationDate         == rInfoItem.m_CreationDate      &&
324          m_ModifiedBy           == rInfoItem.m_ModifiedBy        &&
325          m_ModificationDate     == rInfoItem.m_ModificationDate  &&
326          m_PrintedBy            == rInfoItem.m_PrintedBy         &&
327          m_PrintDate            == rInfoItem.m_PrintDate         &&
328          m_EditingCycles        == rInfoItem.m_EditingCycles     &&
329          m_EditingDuration      == rInfoItem.m_EditingDuration   &&
330          m_Description          == rInfoItem.m_Description       &&
331          m_Keywords             == rInfoItem.m_Keywords          &&
332          m_Contributor          == rInfoItem.m_Contributor       &&
333          m_Coverage             == rInfoItem.m_Coverage          &&
334          m_Identifier           == rInfoItem.m_Identifier        &&
335          m_Publisher            == rInfoItem.m_Publisher         &&
336          m_Relation             == rInfoItem.m_Relation          &&
337          m_Rights               == rInfoItem.m_Rights            &&
338          m_Source               == rInfoItem.m_Source            &&
339          m_Type                 == rInfoItem.m_Type              &&
340          m_Subject              == rInfoItem.m_Subject           &&
341          m_Title                == rInfoItem.m_Title             &&
342          comphelper::ContainerUniquePtrEquals(m_aCustomProperties, rInfoItem.m_aCustomProperties) &&
343          m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
344 }
345 
346 
resetUserData(const OUString & i_rAuthor)347 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
348 {
349     m_Author = i_rAuthor;
350     DateTime now( DateTime::SYSTEM );
351     m_CreationDate = now.GetUNODateTime();
352     m_ModifiedBy = OUString();
353     m_PrintedBy = OUString();
354     m_ModificationDate = util::DateTime();
355     m_PrintDate = util::DateTime();
356     m_EditingDuration = 0;
357     m_EditingCycles = 1;
358 }
359 
360 
UpdateDocumentInfo(const uno::Reference<document::XDocumentProperties> & i_xDocProps,bool i_bDoNotUpdateUserDefined) const361 void SfxDocumentInfoItem::UpdateDocumentInfo(
362         const uno::Reference<document::XDocumentProperties>& i_xDocProps,
363         bool i_bDoNotUpdateUserDefined) const
364 {
365     if (isAutoloadEnabled()) {
366         i_xDocProps->setAutoloadSecs(getAutoloadDelay());
367         i_xDocProps->setAutoloadURL(getAutoloadURL());
368     } else {
369         i_xDocProps->setAutoloadSecs(0);
370         i_xDocProps->setAutoloadURL(OUString());
371     }
372     i_xDocProps->setDefaultTarget(getDefaultTarget());
373     i_xDocProps->setAuthor(getAuthor());
374     i_xDocProps->setCreationDate(getCreationDate());
375     i_xDocProps->setModifiedBy(getModifiedBy());
376     i_xDocProps->setModificationDate(getModificationDate());
377     i_xDocProps->setPrintedBy(getPrintedBy());
378     i_xDocProps->setPrintDate(getPrintDate());
379     i_xDocProps->setEditingCycles(getEditingCycles());
380     i_xDocProps->setEditingDuration(getEditingDuration());
381     i_xDocProps->setDescription(getDescription());
382     i_xDocProps->setKeywords(
383         ::comphelper::string::convertCommaSeparated(getKeywords()));
384 
385     Reference<document::XDocumentProperties2> xDocProps2(i_xDocProps, UNO_QUERY);
386     xDocProps2->setContributor(::comphelper::string::convertCommaSeparated(getContributor()));
387     xDocProps2->setCoverage(getCoverage());
388     xDocProps2->setIdentifier(getIdentifier());
389     xDocProps2->setPublisher(::comphelper::string::convertCommaSeparated(getPublisher()));
390     xDocProps2->setRelation(::comphelper::string::convertCommaSeparated(getRelation()));
391     xDocProps2->setRights(getRights());
392     xDocProps2->setSource(getSource());
393     xDocProps2->setType(getType());
394     xDocProps2->setSubject(getSubject());
395     xDocProps2->setTitle(getTitle());
396 
397     // this is necessary in case of replaying a recorded macro:
398     // in this case, the macro may contain the 4 old user-defined DocumentInfo
399     // fields, but not any of the DocumentInfo properties;
400     // as a consequence, most of the UserDefined properties of the
401     // DocumentProperties would be summarily deleted here, which does not
402     // seem like a good idea.
403     if (i_bDoNotUpdateUserDefined)
404         return;
405 
406     try
407     {
408         Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
409         Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
410         Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
411         const Sequence< beans::Property > lProps = xSetInfo->getProperties();
412         for ( const beans::Property& rProp : lProps )
413         {
414             if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
415             {
416                 xContainer->removeProperty( rProp.Name );
417             }
418         }
419 
420         for (auto const & pProp : m_aCustomProperties)
421         {
422             try
423             {
424                 xContainer->addProperty( pProp->m_sName,
425                     beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
426             }
427             catch ( Exception const & )
428             {
429                 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
430             }
431         }
432     }
433     catch ( Exception const & )
434     {
435         TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
436     }
437 }
438 
439 
SetDeleteUserData(bool bSet)440 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
441 {
442     m_bDeleteUserData = bSet;
443 }
444 
445 
SetUseUserData(bool bSet)446 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
447 {
448     m_bUseUserData = bSet;
449 }
450 
SetUseThumbnailSave(bool bSet)451 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
452 {
453     m_bUseThumbnailSave = bSet;
454 }
455 
GetCustomProperties() const456 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
457 {
458     std::vector< std::unique_ptr<CustomProperty> > aRet;
459     for (auto const & pOtherProp : m_aCustomProperties)
460     {
461         std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
462                                                     pOtherProp->m_aValue ));
463         aRet.push_back( std::move(pProp) );
464     }
465 
466     return aRet;
467 }
468 
ClearCustomProperties()469 void SfxDocumentInfoItem::ClearCustomProperties()
470 {
471     m_aCustomProperties.clear();
472 }
473 
AddCustomProperty(const OUString & sName,const Any & rValue)474 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
475 {
476     std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
477     m_aCustomProperties.push_back( std::move(pProp) );
478 }
479 
480 
SetCmisProperties(const Sequence<document::CmisProperty> & cmisProps)481 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
482 {
483     m_aCmisProperties = cmisProps;
484 }
485 
QueryValue(Any & rVal,sal_uInt8 nMemberId) const486 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
487 {
488     OUString aValue;
489     sal_Int32 nValue = 0;
490     bool bValue = false;
491     bool bIsInt = false;
492     bool bIsString = false;
493     nMemberId &= ~CONVERT_TWIPS;
494     switch ( nMemberId )
495     {
496         case MID_DOCINFO_USEUSERDATA:
497             bValue = IsUseUserData();
498             break;
499         case MID_DOCINFO_USETHUMBNAILSAVE:
500             bValue = IsUseThumbnailSave();
501             break;
502         case MID_DOCINFO_DELETEUSERDATA:
503             bValue = m_bDeleteUserData;
504             break;
505         case MID_DOCINFO_AUTOLOADENABLED:
506             bValue = isAutoloadEnabled();
507             break;
508         case MID_DOCINFO_AUTOLOADSECS:
509             bIsInt = true;
510             nValue = getAutoloadDelay();
511             break;
512         case MID_DOCINFO_AUTOLOADURL:
513             bIsString = true;
514             aValue = getAutoloadURL();
515             break;
516         case MID_DOCINFO_DEFAULTTARGET:
517             bIsString = true;
518             aValue = getDefaultTarget();
519             break;
520         case MID_DOCINFO_DESCRIPTION:
521             bIsString = true;
522             aValue = getDescription();
523             break;
524         case MID_DOCINFO_KEYWORDS:
525             bIsString = true;
526             aValue = getKeywords();
527             break;
528         case MID_DOCINFO_SUBJECT:
529             bIsString = true;
530             aValue = getSubject();
531             break;
532         case MID_DOCINFO_TITLE:
533             bIsString = true;
534             aValue = getTitle();
535             break;
536         default:
537             OSL_FAIL("Wrong MemberId!");
538             return false;
539      }
540 
541     if ( bIsString )
542         rVal <<= aValue;
543     else if ( bIsInt )
544         rVal <<= nValue;
545     else
546         rVal <<= bValue;
547     return true;
548 }
549 
PutValue(const Any & rVal,sal_uInt8 nMemberId)550 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
551 {
552     OUString aValue;
553     sal_Int32 nValue=0;
554     bool bValue = false;
555     bool bRet = false;
556     nMemberId &= ~CONVERT_TWIPS;
557     switch ( nMemberId )
558     {
559         case MID_DOCINFO_USEUSERDATA:
560             bRet = (rVal >>= bValue);
561             if ( bRet )
562                 SetUseUserData( bValue );
563             break;
564         case MID_DOCINFO_USETHUMBNAILSAVE:
565             bRet = (rVal >>=bValue);
566             if ( bRet )
567                 SetUseThumbnailSave( bValue );
568             break;
569         case MID_DOCINFO_DELETEUSERDATA:
570             // QUESTION: deleting user data was done here; seems to be superfluous!
571             bRet = (rVal >>= bValue);
572             if ( bRet )
573                 SetDeleteUserData( bValue );
574             break;
575         case MID_DOCINFO_AUTOLOADENABLED:
576             bRet = (rVal >>= bValue);
577             if ( bRet )
578                 m_isAutoloadEnabled = bValue;
579             break;
580         case MID_DOCINFO_AUTOLOADSECS:
581             bRet = (rVal >>= nValue);
582             if ( bRet )
583                 m_AutoloadDelay = nValue;
584             break;
585         case MID_DOCINFO_AUTOLOADURL:
586             bRet = (rVal >>= aValue);
587             if ( bRet )
588                 m_AutoloadURL = aValue;
589             break;
590         case MID_DOCINFO_DEFAULTTARGET:
591             bRet = (rVal >>= aValue);
592             if ( bRet )
593                 m_DefaultTarget = aValue;
594             break;
595         case MID_DOCINFO_DESCRIPTION:
596             bRet = (rVal >>= aValue);
597             if ( bRet )
598                 setDescription(aValue);
599             break;
600         case MID_DOCINFO_KEYWORDS:
601             bRet = (rVal >>= aValue);
602             if ( bRet )
603                 setKeywords(aValue);
604             break;
605         case MID_DOCINFO_SUBJECT:
606             bRet = (rVal >>= aValue);
607             if ( bRet )
608                 setSubject(aValue);
609             break;
610         case MID_DOCINFO_TITLE:
611             bRet = (rVal >>= aValue);
612             if ( bRet )
613                 setTitle(aValue);
614             break;
615         default:
616             OSL_FAIL("Wrong MemberId!");
617             return false;
618     }
619 
620     return bRet;
621 }
622 
SfxDocumentDescPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)623 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
624     : SfxTabPage(pPage, pController, u"sfx/ui/descriptioninfopage.ui"_ustr, u"DescriptionInfoPage"_ustr, &rItemSet)
625     , m_pInfoItem(nullptr)
626     , m_xTitleEd(m_xBuilder->weld_entry(u"title"_ustr))
627     , m_xThemaEd(m_xBuilder->weld_entry(u"subject"_ustr))
628     , m_xKeywordsEd(m_xBuilder->weld_entry(u"keywords"_ustr))
629     , m_xContributorEd(m_xBuilder->weld_entry(u"contributor"_ustr))
630     , m_xCoverageEd(m_xBuilder->weld_entry(u"coverage"_ustr))
631     , m_xIdentifierEd(m_xBuilder->weld_entry(u"identifier"_ustr))
632     , m_xPublisherEd(m_xBuilder->weld_entry(u"publisher"_ustr))
633     , m_xRelationEd(m_xBuilder->weld_entry(u"relation"_ustr))
634     , m_xRightsEd(m_xBuilder->weld_entry(u"rights"_ustr))
635     , m_xSourceEd(m_xBuilder->weld_entry(u"source"_ustr))
636     , m_xTypeEd(m_xBuilder->weld_entry(u"type"_ustr))
637     , m_xCommentEd(m_xBuilder->weld_text_view(u"comments"_ustr))
638 {
639     m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
640                                    m_xCommentEd->get_height_rows(16));
641 }
642 
~SfxDocumentDescPage()643 SfxDocumentDescPage::~SfxDocumentDescPage()
644 {
645 }
646 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)647 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
648 {
649      return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
650 }
651 
FillItemSet(SfxItemSet * rSet)652 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
653 {
654     // Test whether a change is present
655     const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
656     const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
657     const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
658     const bool bContributorMod = m_xContributorEd->get_value_changed_from_saved();
659     const bool bCoverageMod = m_xCoverageEd->get_value_changed_from_saved();
660     const bool bIdentifierMod = m_xIdentifierEd->get_value_changed_from_saved();
661     const bool bPublisherMod = m_xPublisherEd->get_value_changed_from_saved();
662     const bool bRelationMod = m_xRelationEd->get_value_changed_from_saved();
663     const bool bRightsMod = m_xRightsEd->get_value_changed_from_saved();
664     const bool bSourceMod = m_xSourceEd->get_value_changed_from_saved();
665     const bool bTypeMod = m_xTypeEd->get_value_changed_from_saved();
666     const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
667     if (!(bTitleMod || bThemeMod || bKeywordsMod
668           || bContributorMod || bCoverageMod || bIdentifierMod || bPublisherMod || bRelationMod
669           || bRightsMod || bSourceMod || bTypeMod || bCommentMod))
670     {
671         return false;
672     }
673 
674     // Generating the output data
675     const SfxDocumentInfoItem* pItem = nullptr;
676     SfxDocumentInfoItem* pInfo = nullptr;
677     const SfxItemSet* pExSet = GetDialogExampleSet();
678 
679     if ( pExSet && !(pItem = pExSet->GetItemIfSet( SID_DOCINFO )) )
680         pInfo = m_pInfoItem;
681     else if ( pItem )
682         pInfo = new SfxDocumentInfoItem( *pItem );
683 
684     if ( !pInfo )
685     {
686         SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
687         return false;
688     }
689 
690     if ( bTitleMod )
691     {
692         pInfo->setTitle( m_xTitleEd->get_text() );
693     }
694     if ( bThemeMod )
695     {
696         pInfo->setSubject( m_xThemaEd->get_text() );
697     }
698     if ( bKeywordsMod )
699     {
700         pInfo->setKeywords( m_xKeywordsEd->get_text() );
701     }
702     if (bContributorMod)
703     {
704         pInfo->setContributor(m_xContributorEd->get_text());
705     }
706     if (bCoverageMod)
707     {
708         pInfo->setCoverage(m_xCoverageEd->get_text());
709     }
710     if (bIdentifierMod)
711     {
712         pInfo->setIdentifier(m_xIdentifierEd->get_text());
713     }
714     if (bPublisherMod)
715     {
716         pInfo->setPublisher(m_xPublisherEd->get_text());
717     }
718     if (bRelationMod)
719     {
720         pInfo->setRelation(m_xRelationEd->get_text());
721     }
722     if (bRightsMod)
723     {
724         pInfo->setRights(m_xRightsEd->get_text());
725     }
726     if (bSourceMod)
727     {
728         pInfo->setSource(m_xSourceEd->get_text());
729     }
730     if (bTypeMod)
731     {
732         pInfo->setType(m_xTypeEd->get_text());
733     }
734     if ( bCommentMod )
735     {
736         pInfo->setDescription( m_xCommentEd->get_text() );
737     }
738     rSet->Put( *pInfo );
739     // ptr compare OK, pInfo was created above as temporary data holder
740     if ( !areSfxPoolItemPtrsEqual(pInfo, m_pInfoItem) )
741     {
742         delete pInfo;
743     }
744 
745     return true;
746 }
747 
Reset(const SfxItemSet * rSet)748 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
749 {
750     m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
751 
752     m_xTitleEd->set_text(m_pInfoItem->getTitle());
753     m_xThemaEd->set_text(m_pInfoItem->getSubject());
754     m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
755     m_xContributorEd->set_text(m_pInfoItem->getContributor());
756     m_xCoverageEd->set_text(m_pInfoItem->getCoverage());
757     m_xIdentifierEd->set_text(m_pInfoItem->getIdentifier());
758     m_xPublisherEd->set_text(m_pInfoItem->getPublisher());
759     m_xRelationEd->set_text(m_pInfoItem->getRelation());
760     m_xRightsEd->set_text(m_pInfoItem->getRights());
761     m_xSourceEd->set_text(m_pInfoItem->getSource());
762     m_xTypeEd->set_text(m_pInfoItem->getType());
763     m_xCommentEd->set_text(m_pInfoItem->getDescription());
764 
765     m_xTitleEd->save_value();
766     m_xThemaEd->save_value();
767     m_xKeywordsEd->save_value();
768     m_xContributorEd->save_value();
769     m_xCoverageEd->save_value();
770     m_xIdentifierEd->save_value();
771     m_xPublisherEd->save_value();
772     m_xRelationEd->save_value();
773     m_xRightsEd->save_value();
774     m_xSourceEd->save_value();
775     m_xTypeEd->save_value();
776     m_xCommentEd->save_value();
777 
778     const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
779     if (pROItem && pROItem->GetValue())
780     {
781         m_xTitleEd->set_editable(false);
782         m_xThemaEd->set_editable(false);
783         m_xKeywordsEd->set_editable(false);
784         m_xContributorEd->set_editable(false);
785         m_xCoverageEd->set_editable(false);
786         m_xIdentifierEd->set_editable(false);
787         m_xPublisherEd->set_editable(false);
788         m_xRelationEd->set_editable(false);
789         m_xRightsEd->set_editable(false);
790         m_xSourceEd->set_editable(false);
791         m_xTypeEd->set_editable(false);
792         m_xCommentEd->set_editable(false);
793     }
794 }
795 
SfxDocumentPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)796 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
797     : SfxTabPage(pPage, pController, u"sfx/ui/documentinfopage.ui"_ustr, u"DocumentInfoPage"_ustr, &rItemSet)
798     , bEnableUseUserData( false )
799     , bHandleDelete( false )
800     , m_xBmp(m_xBuilder->weld_image(u"icon"_ustr))
801     , m_xNameED(m_xBuilder->weld_label(u"nameed"_ustr))
802     , m_xChangePassBtn(m_xBuilder->weld_button(u"changepass"_ustr))
803     , m_xShowTypeFT(m_xBuilder->weld_label(u"showtype"_ustr))
804     , m_xFileValEd(m_xBuilder->weld_link_button(u"showlocation"_ustr))
805     , m_xShowSizeFT(m_xBuilder->weld_label(u"showsize"_ustr))
806     , m_xCreateValFt(m_xBuilder->weld_label(u"showcreate"_ustr))
807     , m_xChangeValFt(m_xBuilder->weld_label(u"showmodify"_ustr))
808     , m_xSignedValFt(m_xBuilder->weld_label(u"showsigned"_ustr))
809     , m_xSignatureBtn(m_xBuilder->weld_button(u"signature"_ustr))
810     , m_xPrintValFt(m_xBuilder->weld_label(u"showprint"_ustr))
811     , m_xTimeLogValFt(m_xBuilder->weld_label(u"showedittime"_ustr))
812     , m_xDocNoValFt(m_xBuilder->weld_label(u"showrevision"_ustr))
813     , m_xUseUserDataCB(m_xBuilder->weld_check_button(u"userdatacb"_ustr))
814     , m_xDeleteBtn(m_xBuilder->weld_button(u"reset"_ustr))
815     , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button(u"thumbnailsavecb"_ustr))
816     , m_xTemplFt(m_xBuilder->weld_label(u"templateft"_ustr))
817     , m_xTemplValFt(m_xBuilder->weld_label(u"showtemplate"_ustr))
818     , m_xImagePreferredDpiCheckButton(m_xBuilder->weld_check_button(u"image-preferred-dpi-checkbutton"_ustr))
819     , m_xImagePreferredDpiComboBox(m_xBuilder->weld_combo_box(u"image-preferred-dpi-combobox"_ustr))
820 {
821     m_xUseUserDataCB->set_accessible_description(SfxResId(STR_A11Y_DESC_USERDATA));
822 
823     m_aUnknownSize = m_xShowSizeFT->get_label();
824     m_xShowSizeFT->set_label(OUString());
825 
826     m_aMultiSignedStr = m_xSignedValFt->get_label();
827     m_xSignedValFt->set_label(OUString());
828     m_xImagePreferredDpiComboBox->set_entry_width_chars(5); // "width in chars" in Glade not effective
829 
830     ImplUpdateSignatures();
831     ImplCheckPasswordState();
832     m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
833     m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
834     if (comphelper::LibreOfficeKit::isActive())
835         m_xSignatureBtn->hide();
836     m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
837     m_xImagePreferredDpiCheckButton->connect_toggled(LINK(this, SfxDocumentPage, ImagePreferredDPICheckBoxClicked));
838 
839     // [i96288] Check if the document signature command is enabled
840     // on the main list enable/disable the pushbutton accordingly
841     SvtCommandOptions aCmdOptions;
842     if ( aCmdOptions.LookupDisabled( u"Signature"_ustr ) )
843         m_xSignatureBtn->set_sensitive(false);
844 }
845 
~SfxDocumentPage()846 SfxDocumentPage::~SfxDocumentPage()
847 {
848     if (m_xPasswordDialog)
849     {
850         m_xPasswordDialog->Response(RET_CANCEL);
851         m_xPasswordDialog.reset();
852     }
853 }
854 
IMPL_LINK_NOARG(SfxDocumentPage,DeleteHdl,weld::Button &,void)855 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
856 {
857     OUString aName;
858     if (bEnableUseUserData && m_xUseUserDataCB->get_active())
859         aName = SvtUserOptions().GetFullName();
860     const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
861     DateTime now( DateTime::SYSTEM );
862     util::DateTime uDT( now.GetUNODateTime() );
863     m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
864     m_xChangeValFt->set_label( u""_ustr );
865     m_xPrintValFt->set_label( u""_ustr );
866     m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( tools::Duration() ) );
867     m_xDocNoValFt->set_label(OUString('1'));
868     bHandleDelete = true;
869 }
870 
IMPL_LINK_NOARG(SfxDocumentPage,SignatureHdl,weld::Button &,void)871 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
872 {
873     SfxObjectShell* pDoc = SfxObjectShell::Current();
874     if( pDoc )
875     {
876         pDoc->SignDocumentContent(GetFrameWeld(), [this] (bool /*bHaveWeSigned*/) {
877             ImplUpdateSignatures();
878         });
879     }
880 }
881 
IMPL_LINK_NOARG(SfxDocumentPage,ImagePreferredDPICheckBoxClicked,weld::Toggleable &,void)882 IMPL_LINK_NOARG(SfxDocumentPage, ImagePreferredDPICheckBoxClicked, weld::Toggleable&, void)
883 {
884     bool bEnabled = m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE;
885     m_xImagePreferredDpiComboBox->set_sensitive(bEnabled);
886 }
887 
IMPL_LINK_NOARG(SfxDocumentPage,ChangePassHdl,weld::Button &,void)888 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
889 {
890     SfxObjectShell* pShell = SfxObjectShell::Current();
891     do
892     {
893         if (!pShell)
894             break;
895         SfxItemSet& rMedSet = pShell->GetMedium()->GetItemSet();
896         std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
897         if (!pFilter)
898             break;
899         if (comphelper::LibreOfficeKit::isActive())
900         {
901             // MS Types support max len of 15 characters while OOXML is "unlimited"
902             const sal_uInt16 maxPwdLen = sfx2::IsMSType(pFilter) && !sfx2::IsOOXML(pFilter) ? 15 : 0;
903             // handle the pwd dialog asynchronously
904             VclAbstractDialogFactory * pFact = VclAbstractDialogFactory::Create();
905             m_xPasswordDialog = pFact->CreatePasswordToOpenModifyDialog(GetFrameWeld(), maxPwdLen, false);
906             m_xPasswordDialog->AllowEmpty(); // needed to remove password
907             m_xPasswordDialog->StartExecuteAsync([this, pFilter=std::move(pFilter), &rMedSet, pShell](sal_Int32 nResult)
908             {
909                 if (nResult == RET_OK)
910                 {
911                     sfx2::SetPassword(pFilter, &rMedSet, m_xPasswordDialog->GetPasswordToOpen(),
912                                       m_xPasswordDialog->GetPasswordToOpen(), true);
913                     tools::JsonWriter payloadJson;
914                     payloadJson.put("password", m_xPasswordDialog->GetPasswordToOpen());
915                     payloadJson.put("isToModify", false);
916 
917                     SfxViewShell *pViewShell = SfxViewShell::Current();
918                     if (pViewShell)
919                         pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_PASSWORD_RESET, payloadJson.finishAndGetAsOString());
920 
921                     pShell->SetModified();
922                 }
923                 m_xPasswordDialog->disposeOnce();
924             });
925         } else {
926             sfx2::RequestPassword(pFilter, OUString(), &rMedSet, GetFrameWeld()->GetXWindow());
927             pShell->SetModified();
928         }
929     }
930     while (false);
931 }
932 
ImplUpdateSignatures()933 void SfxDocumentPage::ImplUpdateSignatures()
934 {
935     SfxObjectShell* pDoc = SfxObjectShell::Current();
936     if ( !pDoc )
937         return;
938 
939     SfxMedium* pMedium = pDoc->GetMedium();
940     if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
941         return;
942 
943     Reference< security::XDocumentDigitalSignatures > xD;
944     try
945     {
946         xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
947         xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
948     }
949     catch ( const css::uno::DeploymentException& )
950     {
951     }
952     OUString s;
953     Sequence< security::DocumentSignatureInformation > aInfos;
954 
955     if ( xD.is() )
956         aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
957                                                       uno::Reference< io::XInputStream >() );
958     if ( aInfos.getLength() > 1 )
959         s = m_aMultiSignedStr;
960     else if ( aInfos.getLength() == 1 )
961     {
962         const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
963         s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
964             comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
965     }
966     m_xSignedValFt->set_label(s);
967 }
968 
ImplCheckPasswordState()969 void SfxDocumentPage::ImplCheckPasswordState()
970 {
971     SfxObjectShell* pShell = SfxObjectShell::Current();
972     do
973     {
974         if (!pShell)
975             break;
976         const SfxUnoAnyItem* pEncryptionDataItem = pShell->GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
977         uno::Sequence< beans::NamedValue > aEncryptionData;
978         if (pEncryptionDataItem)
979             pEncryptionDataItem->GetValue() >>= aEncryptionData;
980         else
981              break;
982 
983         if (!aEncryptionData.hasElements())
984              break;
985         m_xChangePassBtn->set_sensitive(true);
986         return;
987     }
988     while (false);
989     m_xChangePassBtn->set_sensitive(comphelper::LibreOfficeKit::isActive());
990 }
991 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)992 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
993 {
994      return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
995 }
996 
EnableUseUserData()997 void SfxDocumentPage::EnableUseUserData()
998 {
999     bEnableUseUserData = true;
1000     m_xUseUserDataCB->show();
1001     m_xDeleteBtn->show();
1002 }
1003 
FillItemSet(SfxItemSet * rSet)1004 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
1005 {
1006     bool bRet = false;
1007 
1008     if ( !bHandleDelete && bEnableUseUserData &&
1009          m_xUseUserDataCB->get_state_changed_from_saved() )
1010     {
1011         const SfxItemSet* pExpSet = GetDialogExampleSet();
1012         const SfxDocumentInfoItem* pInfoItem;
1013 
1014         if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO ) ) )
1015         {
1016             bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1017             const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
1018             rSet->Put( *pInfoItem );
1019             bRet = true;
1020         }
1021     }
1022 
1023     if ( bHandleDelete )
1024     {
1025         const SfxItemSet* pExpSet = GetDialogExampleSet();
1026         const SfxDocumentInfoItem* pInfoItem;
1027         if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
1028         {
1029             bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
1030             SfxDocumentInfoItem newItem( *pInfoItem );
1031             newItem.resetUserData( bUseAuthor
1032                 ? SvtUserOptions().GetFullName()
1033                 : OUString() );
1034             const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1035             newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1036 
1037             newItem.SetDeleteUserData( true );
1038             rSet->Put( newItem );
1039             bRet = true;
1040         }
1041     }
1042 
1043     if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
1044     {
1045         const SfxItemSet* pExpSet = GetDialogExampleSet();
1046         const SfxDocumentInfoItem* pInfoItem;
1047 
1048         if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
1049         {
1050             bool bUseThumbnail = ( TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state() );
1051             const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave( bUseThumbnail );
1052             rSet->Put( *pInfoItem );
1053             bRet = true;
1054         }
1055     }
1056 
1057     SfxObjectShell* pDocSh = SfxObjectShell::Current();
1058     if (pDocSh)
1059     {
1060         uno::Reference<lang::XMultiServiceFactory> xFac(pDocSh->GetModel(), uno::UNO_QUERY);
1061         if (xFac.is())
1062         {
1063             uno::Reference<beans::XPropertySet> xProps(xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
1064             if (xProps.is())
1065             {
1066                 sal_Int32 nImagePreferredDPI = 0;
1067                 if (m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE)
1068                 {
1069                     OUString aImagePreferredDPIString = m_xImagePreferredDpiComboBox->get_active_text();
1070                     nImagePreferredDPI = aImagePreferredDPIString.toInt32();
1071                 }
1072                 xProps->setPropertyValue(u"ImagePreferredDPI"_ustr, uno::Any(nImagePreferredDPI));
1073             }
1074         }
1075     }
1076 
1077     return bRet;
1078 }
1079 
Reset(const SfxItemSet * rSet)1080 void SfxDocumentPage::Reset( const SfxItemSet* rSet )
1081 {
1082     // Determine the document information
1083     const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
1084 
1085     // template data
1086     if (rInfoItem.HasTemplate())
1087     {
1088         const OUString& rName = rInfoItem.getTemplateName();
1089         if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
1090             m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
1091         else
1092             m_xTemplValFt->set_label(rName);
1093     }
1094     else
1095     {
1096         m_xTemplFt->hide();
1097         m_xTemplValFt->hide();
1098     }
1099 
1100     // determine file name
1101     OUString aFile( rInfoItem.GetValue() );
1102     OUString aFactory( aFile );
1103     if ( aFile.getLength() > 2 && aFile[0] == '[' )
1104     {
1105         sal_Int32 nPos = aFile.indexOf( ']' );
1106         aFactory = aFile.copy( 1, nPos-1  );
1107         aFile = aFile.copy( nPos+1 );
1108     }
1109 
1110     // determine name
1111     INetURLObject aURL(aFile);
1112     OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1113     if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
1114         aName = SfxResId( STR_NONAME );
1115     m_xNameED->set_label( aName );
1116 
1117     // determine context symbol
1118     aURL.SetSmartProtocol( INetProtocol::File );
1119     aURL.SetSmartURL( aFactory);
1120     const OUString aMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1121     OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
1122     m_xBmp->set_from_icon_name(aImage);
1123 
1124     // determine size and type
1125     OUString aSizeText( m_aUnknownSize );
1126     // we might already know the size as an optional argument passed to .uno:SetDocumentProperties
1127     sal_Int64 nSize = rInfoItem.getFileSize();
1128     // otherwise, for some protocols we can reliably query for it
1129     if (nSize == -1 && (aURL.GetProtocol() == INetProtocol::File || aURL.isAnyKnownWebDAVScheme()))
1130         nSize = SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1131     if (nSize != -1)
1132         aSizeText = CreateSizeText( nSize );
1133     m_xShowSizeFT->set_label( aSizeText );
1134 
1135     OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(aMainURL) );
1136     if ( aDescription.isEmpty() )
1137         aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
1138     m_xShowTypeFT->set_label( aDescription );
1139 
1140     // determine location
1141     // online we don't know file location so we just set it as the name
1142     if (comphelper::LibreOfficeKit::isActive())
1143     {
1144         m_xFileValEd->set_label(aName);
1145         m_xFileValEd->set_uri(aName);
1146 
1147         // Disable setting/changing password on text files.
1148         // Perhaps this needs to be done for both Online and Desktop.
1149         OUString sExtension(INetURLObject(aMainURL).getExtension());
1150         if (!sExtension.isEmpty())
1151         {
1152             sExtension = sExtension.toAsciiLowerCase();
1153             if (sExtension == "txt" || sExtension == "csv")
1154                 m_xChangePassBtn->set_sensitive(false);
1155         }
1156     }
1157     else
1158     {
1159         aURL.SetSmartURL( aFile);
1160         if ( aURL.GetProtocol() == INetProtocol::File )
1161         {
1162             INetURLObject aPath(std::move(aURL));
1163             aPath.setFinalSlash();
1164             aPath.removeSegment();
1165             // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
1166             aPath.removeFinalSlash();
1167             OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
1168             m_xFileValEd->set_label(aText);
1169             OUString aURLStr;
1170             osl::FileBase::getFileURLFromSystemPath(aText, aURLStr);
1171             m_xFileValEd->set_uri(aURLStr);
1172         }
1173         else if (aURL.GetProtocol() != INetProtocol::PrivSoffice)
1174         {
1175             m_xFileValEd->set_label(aURL.GetPartBeforeLastName());
1176             m_xFileValEd->set_uri(m_xFileValEd->get_label());
1177         }
1178     }
1179 
1180 
1181     // handle access data
1182     bool bUseUserData = rInfoItem.IsUseUserData();
1183     const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
1184     m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
1185         rInfoItem.getCreationDate(), rLocaleWrapper ) );
1186     util::DateTime aTime( rInfoItem.getModificationDate() );
1187     if ( aTime.Month > 0 )
1188         m_xChangeValFt->set_label( ConvertDateTime_Impl(
1189             rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
1190     aTime = rInfoItem.getPrintDate();
1191     if ( aTime.Month > 0 )
1192         m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
1193             aTime, rLocaleWrapper ) );
1194     const tools::Long nTime = rInfoItem.getEditingDuration();
1195     if ( bUseUserData )
1196     {
1197         assert(SAL_MIN_INT32 <= nTime/86400 && nTime/86400 <= SAL_MAX_INT32);
1198         const tools::Duration aD( static_cast<sal_Int32>(nTime)/86400,
1199                 (nTime%86400)/3600, (nTime%3600)/60, nTime%60, 0);
1200         m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aD ) );
1201         m_xDocNoValFt->set_label( OUString::number(
1202             rInfoItem.getEditingCycles() ) );
1203     }
1204 
1205     bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1206 
1207     // Check for cmis properties where otherwise unavailable
1208     if ( rInfoItem.isCmisDocument( ) )
1209     {
1210         const uno::Sequence< document::CmisProperty >& aCmisProps = rInfoItem.GetCmisProperties();
1211         for ( const auto& rCmisProp : aCmisProps )
1212         {
1213             if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1214                  aSizeText == m_aUnknownSize )
1215             {
1216                 Sequence< sal_Int64 > seqValue;
1217                 rCmisProp.Value >>= seqValue;
1218                 SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1219                         Application::GetSettings().GetLanguageTag().getLanguageType() );
1220                 sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1221                 if ( seqValue.hasElements() )
1222                 {
1223                     OUString sValue = aNumberFormatter.GetInputLineString( seqValue[0], nIndex );
1224                     m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1225                 }
1226             }
1227 
1228             util::DateTime uDT;
1229             OUString emptyDate = ConvertDateTime_Impl( u"", uDT, rLocaleWrapper );
1230             if ( rCmisProp.Id == "cmis:creationDate" &&
1231                  (m_xCreateValFt->get_label() == emptyDate ||
1232                   m_xCreateValFt->get_label().isEmpty()))
1233             {
1234                 Sequence< util::DateTime > seqValue;
1235                 rCmisProp.Value >>= seqValue;
1236                 if ( seqValue.hasElements() )
1237                 {
1238                     m_xCreateValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1239                 }
1240             }
1241             if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1242                  (m_xChangeValFt->get_label() == emptyDate ||
1243                   m_xChangeValFt->get_label().isEmpty()))
1244             {
1245                 Sequence< util::DateTime > seqValue;
1246                 rCmisProp.Value >>= seqValue;
1247                 if ( seqValue.hasElements() )
1248                 {
1249                     m_xChangeValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1250                 }
1251             }
1252         }
1253     }
1254 
1255     m_xUseUserDataCB->set_active(bUseUserData);
1256     m_xUseUserDataCB->save_state();
1257     m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1258     bHandleDelete = false;
1259     m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1260     m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1261     m_xUseThumbnailSaveCB->save_state();
1262 
1263     SfxObjectShell* pDocSh = SfxObjectShell::Current();
1264     sal_Int32 nImagePreferredDPI = 0;
1265     if (pDocSh)
1266     {
1267         try
1268         {
1269             uno::Reference< lang::XMultiServiceFactory > xFac( pDocSh->GetModel(), uno::UNO_QUERY );
1270             if (xFac)
1271             {
1272                 uno::Reference< beans::XPropertySet > xProps( xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY );
1273                 if (xProps)
1274                     xProps->getPropertyValue(u"ImagePreferredDPI"_ustr) >>= nImagePreferredDPI;
1275             }
1276         }
1277         catch( uno::Exception& )
1278         {
1279         }
1280     }
1281     if (nImagePreferredDPI > 0)
1282     {
1283         m_xImagePreferredDpiCheckButton->set_state(TRISTATE_TRUE);
1284         m_xImagePreferredDpiComboBox->set_sensitive(true);
1285         m_xImagePreferredDpiComboBox->set_entry_text(OUString::number(nImagePreferredDPI));
1286     }
1287     else
1288     {
1289         m_xImagePreferredDpiCheckButton->set_state(TRISTATE_FALSE);
1290         m_xImagePreferredDpiComboBox->set_sensitive(false);
1291         m_xImagePreferredDpiComboBox->set_entry_text(u""_ustr);
1292     }
1293 
1294 }
1295 
SfxDocumentInfoDialog(weld::Window * pParent,const SfxItemSet & rItemSet)1296 SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1297     : SfxTabDialogController(pParent, u"sfx/ui/documentpropertiesdialog.ui"_ustr,
1298                              u"DocumentPropertiesDialog"_ustr, &rItemSet)
1299 {
1300     const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1301 
1302 #ifdef DBG_UTIL
1303     const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1304     DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1305 #endif
1306 
1307      // Determine the Titles
1308     OUString aTitle(m_xDialog->get_title());
1309     const SfxStringItem* pItem = rItemSet.GetItemIfSet( SID_EXPLORER_PROPS_START, false );
1310     if ( !pItem )
1311     {
1312         // File name
1313         const OUString& aFile( rInfoItem.GetValue() );
1314 
1315         INetURLObject aURL;
1316         aURL.SetSmartProtocol( INetProtocol::File );
1317         aURL.SetSmartURL( aFile);
1318         if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1319         {
1320             OUString aLastName( aURL.GetLastName() );
1321             if ( !aLastName.isEmpty() )
1322                 aTitle = aTitle.replaceFirst("%1", aLastName);
1323             else
1324                 aTitle = aTitle.replaceFirst("%1", aFile);
1325         }
1326         else
1327             aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1328     }
1329     else
1330     {
1331         aTitle = aTitle.replaceFirst("%1", pItem->GetValue());
1332     }
1333     m_xDialog->set_title(aTitle);
1334 
1335     // Property Pages
1336     AddTabPage(u"general"_ustr, TabResId(RID_TAB_ORGANIZER.aLabel), SfxDocumentPage::Create,
1337                RID_L + RID_TAB_ORGANIZER.sIconName);
1338     AddTabPage(u"description"_ustr, TabResId(RID_TAB_DESCRIPTION.aLabel), SfxDocumentDescPage::Create,
1339                RID_L + RID_TAB_DESCRIPTION.sIconName);
1340 
1341     AddTabPage(u"customprops"_ustr, TabResId(RID_TAB_CUSTOM.aLabel),
1342                SfxCustomPropertiesPage::Create, RID_L + RID_TAB_CUSTOM.sIconName);
1343 
1344     if (rInfoItem.isCmisDocument())
1345         AddTabPage(u"cmisprops"_ustr, TabResId(RID_TAB_CMIS.aLabel),
1346                    SfxCmisPropertiesPage::Create, RID_L + RID_TAB_CMIS.sIconName);
1347     // Disable security page for online as not fully asynced yet
1348     if (!comphelper::LibreOfficeKit::isActive())
1349         AddTabPage(u"security"_ustr, TabResId(RID_TAB_SECURITY.aLabel), SfxSecurityPage::Create,
1350                    RID_L + RID_TAB_SECURITY.sIconName);
1351 }
1352 
PageCreated(const OUString & rId,SfxTabPage & rPage)1353 void SfxDocumentInfoDialog::PageCreated(const OUString& rId, SfxTabPage &rPage)
1354 {
1355     if (rId == "general")
1356         static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1357 }
1358 
AddFontTabPage()1359 void SfxDocumentInfoDialog::AddFontTabPage()
1360 {
1361     AddTabPage(u"font"_ustr, TabResId(RID_TAB_FONT.aLabel),
1362                SfxDocumentFontsPage::Create, RID_L + RID_TAB_FONT.sIconName);
1363 }
1364 
1365 // class CustomPropertiesYesNoButton -------------------------------------
1366 
CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,std::unique_ptr<weld::RadioButton> xYesButton,std::unique_ptr<weld::RadioButton> xNoButton)1367 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1368                                                          std::unique_ptr<weld::RadioButton> xYesButton,
1369                                                          std::unique_ptr<weld::RadioButton> xNoButton)
1370     : m_xTopLevel(std::move(xTopLevel))
1371     , m_xYesButton(std::move(xYesButton))
1372     , m_xNoButton(std::move(xNoButton))
1373 {
1374     CheckNo();
1375 }
1376 
~CustomPropertiesYesNoButton()1377 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1378 {
1379 }
1380 
1381 
DurationDialog_Impl(weld::Widget * pParent,const util::Duration & rDuration)1382 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1383     : GenericDialogController(pParent, u"sfx/ui/editdurationdialog.ui"_ustr, u"EditDurationDialog"_ustr)
1384     , m_xNegativeCB(m_xBuilder->weld_check_button(u"negative"_ustr))
1385     , m_xYearNF(m_xBuilder->weld_spin_button(u"years"_ustr))
1386     , m_xMonthNF(m_xBuilder->weld_spin_button(u"months"_ustr))
1387     , m_xDayNF(m_xBuilder->weld_spin_button(u"days"_ustr))
1388     , m_xHourNF(m_xBuilder->weld_spin_button(u"hours"_ustr))
1389     , m_xMinuteNF(m_xBuilder->weld_spin_button(u"minutes"_ustr))
1390     , m_xSecondNF(m_xBuilder->weld_spin_button(u"seconds"_ustr))
1391     , m_xMSecondNF(m_xBuilder->weld_spin_button(u"milliseconds"_ustr))
1392 {
1393     m_xNegativeCB->set_active(rDuration.Negative);
1394     m_xYearNF->set_value(rDuration.Years);
1395     m_xMonthNF->set_value(rDuration.Months);
1396     m_xDayNF->set_value(rDuration.Days);
1397     m_xHourNF->set_value(rDuration.Hours);
1398     m_xMinuteNF->set_value(rDuration.Minutes);
1399     m_xSecondNF->set_value(rDuration.Seconds);
1400     m_xMSecondNF->set_value(rDuration.NanoSeconds);
1401 }
1402 
GetDuration() const1403 util::Duration  DurationDialog_Impl::GetDuration() const
1404 {
1405     util::Duration  aRet;
1406     aRet.Negative = m_xNegativeCB->get_active();
1407     aRet.Years = m_xYearNF->get_value();
1408     aRet.Months = m_xMonthNF->get_value();
1409     aRet.Days = m_xDayNF->get_value();
1410     aRet.Hours  = m_xHourNF->get_value();
1411     aRet.Minutes = m_xMinuteNF->get_value();
1412     aRet.Seconds = m_xSecondNF->get_value();
1413     aRet.NanoSeconds = m_xMSecondNF->get_value();
1414     return aRet;
1415 }
1416 
CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,std::unique_ptr<weld::Button> xEditButton)1417 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1418                                                              std::unique_ptr<weld::Button> xEditButton)
1419     : m_xEntry(std::move(xEntry))
1420     , m_xEditButton(std::move(xEditButton))
1421 {
1422     m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1423     SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1424 }
1425 
set_visible(bool bVisible)1426 void CustomPropertiesDurationField::set_visible(bool bVisible)
1427 {
1428     m_xEntry->set_visible(bVisible);
1429     m_xEditButton->set_visible(bVisible);
1430 }
1431 
SetDuration(const util::Duration & rDuration)1432 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1433 {
1434     m_aDuration = rDuration;
1435     OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1436         SfxResId(SFX_ST_DURATION_FORMAT);
1437     sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1438     sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1439     sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days   ) );
1440     sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours  ) );
1441     sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1442     sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1443     m_xEntry->set_text(sText);
1444 }
1445 
IMPL_LINK(CustomPropertiesDurationField,ClickHdl,weld::Button &,rButton,void)1446 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1447 {
1448     m_xDurationDialog = std::make_shared<DurationDialog_Impl>(&rButton, GetDuration());
1449     weld::DialogController::runAsync(m_xDurationDialog, [&](sal_Int32 response)
1450     {
1451         if (response == RET_OK)
1452         {
1453             SetDuration(m_xDurationDialog->GetDuration());
1454         }
1455     });
1456 }
1457 
~CustomPropertiesDurationField()1458 CustomPropertiesDurationField::~CustomPropertiesDurationField()
1459 {
1460     if (m_xDurationDialog)
1461         m_xDurationDialog->response(RET_CANCEL);
1462 }
1463 
1464 namespace
1465 {
fillNameBox(weld::ComboBox & rNameBox)1466     void fillNameBox(weld::ComboBox& rNameBox)
1467     {
1468         for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1469             rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1470         Size aSize(rNameBox.get_preferred_size());
1471         rNameBox.set_size_request(aSize.Width(), aSize.Height());
1472     }
1473 
fillTypeBox(weld::ComboBox & rTypeBox)1474     void fillTypeBox(weld::ComboBox& rTypeBox)
1475     {
1476         for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1477         {
1478             OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1479             rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1480         }
1481         rTypeBox.set_active(0);
1482         Size aSize(rTypeBox.get_preferred_size());
1483         rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1484     }
1485 }
1486 
1487 // struct CustomPropertyLine ---------------------------------------------
CustomPropertyLine(CustomPropertiesWindow * pParent,weld::Widget * pContainer)1488 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1489     : m_pParent(pParent)
1490     , m_xBuilder(Application::CreateBuilder(pContainer, u"sfx/ui/linefragment.ui"_ustr))
1491     , m_xLine(m_xBuilder->weld_container(u"lineentry"_ustr))
1492     , m_xNameBox(m_xBuilder->weld_combo_box(u"namebox"_ustr))
1493     , m_xTypeBox(m_xBuilder->weld_combo_box(u"typebox"_ustr))
1494     , m_xValueEdit(m_xBuilder->weld_entry(u"valueedit"_ustr))
1495     , m_xDateTimeBox(m_xBuilder->weld_widget(u"datetimebox"_ustr))
1496     , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr))))
1497     , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr)))
1498     , m_xDurationBox(m_xBuilder->weld_widget(u"durationbox"_ustr))
1499     , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry(u"duration"_ustr),
1500                                                          m_xBuilder->weld_button(u"durationbutton"_ustr)))
1501     , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget(u"yesno"_ustr),
1502                                                      m_xBuilder->weld_radio_button(u"yes"_ustr),
1503                                                      m_xBuilder->weld_radio_button(u"no"_ustr)))
1504     , m_xRemoveButton(m_xBuilder->weld_button(u"remove"_ustr))
1505     , m_bTypeLostFocus( false )
1506 {
1507     fillNameBox(*m_xNameBox);
1508     fillTypeBox(*m_xTypeBox);
1509 
1510     m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1511     m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1512     m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1513     //add lose focus handlers of date/time fields
1514     m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1515 }
1516 
Clear()1517 void CustomPropertyLine::Clear()
1518 {
1519     m_xNameBox->set_active(-1);
1520     m_xValueEdit->set_text(OUString());
1521 
1522 }
1523 
Hide()1524 void CustomPropertyLine::Hide()
1525 {
1526     m_xLine->hide();
1527 }
1528 
CustomPropertiesWindow(weld::Container & rParent,weld::Label & rHeaderAccName,weld::Label & rHeaderAccType,weld::Label & rHeaderAccValue)1529 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1530                                                weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1531     : m_nHeight(0)
1532     , m_nLineHeight(0)
1533     , m_nScrollPos(0)
1534     , m_pCurrentLine(nullptr)
1535     , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1536                          Application::GetSettings().GetLanguageTag().getLanguageType())
1537     , m_aEditLoseFocusIdle("sfx2 CustomPropertiesWindow loseFocusIdle")
1538     , m_aBoxLoseFocusIdle("sfx2 CustomPropertiesWindow m_aBoxLoseFocusIdle")
1539     , m_rBody(rParent)
1540     , m_rHeaderAccName(rHeaderAccName)
1541     , m_rHeaderAccType(rHeaderAccType)
1542     , m_rHeaderAccValue(rHeaderAccValue)
1543 {
1544     m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1545     m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1546     m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1547     m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1548 }
1549 
~CustomPropertiesWindow()1550 CustomPropertiesWindow::~CustomPropertiesWindow()
1551 {
1552     m_aEditLoseFocusIdle.Stop();
1553     m_aBoxLoseFocusIdle.Stop();
1554 
1555     m_pCurrentLine = nullptr;
1556 }
1557 
DoTypeHdl(const weld::ComboBox & rBox)1558 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1559 {
1560     auto nType = rBox.get_active_id().toInt32();
1561     m_xValueEdit->set_visible( (Custom_Type_Text == nType) || (Custom_Type_Number == nType) );
1562     m_xDateTimeBox->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1563     m_xDateField->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1564     m_xTimeField->set_visible( Custom_Type_Datetime == nType );
1565     m_xDurationBox->set_visible( Custom_Type_Duration == nType );
1566     m_xDurationField->set_visible( Custom_Type_Duration == nType );
1567     m_xYesNoButton->set_visible( Custom_Type_Boolean == nType );
1568 }
1569 
IMPL_LINK(CustomPropertyLine,TypeHdl,weld::ComboBox &,rBox,void)1570 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1571 {
1572     DoTypeHdl(rBox);
1573 }
1574 
Remove(const CustomPropertyLine * pLine)1575 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1576 {
1577     StoreCustomProperties();
1578 
1579     auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1580                     [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1581     if ( pFound != m_aCustomPropertiesLines.end() )
1582     {
1583         sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1584         sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1585         m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1586 
1587         ReloadLinesContent();
1588     }
1589 
1590     m_aRemovedHdl.Call(nullptr);
1591 }
1592 
IMPL_LINK_NOARG(CustomPropertyLine,RemoveHdl,weld::Button &,void)1593 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1594 {
1595     m_pParent->Remove(this);
1596 }
1597 
EditLoseFocus(CustomPropertyLine * pLine)1598 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1599 {
1600     m_pCurrentLine = pLine;
1601     m_aEditLoseFocusIdle.Start();
1602 }
1603 
IMPL_LINK_NOARG(CustomPropertyLine,EditLoseFocusHdl,weld::Widget &,void)1604 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1605 {
1606     if (!m_bTypeLostFocus)
1607         m_pParent->EditLoseFocus(this);
1608     else
1609         m_bTypeLostFocus = false;
1610 }
1611 
BoxLoseFocus(CustomPropertyLine * pLine)1612 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1613 {
1614     m_pCurrentLine = pLine;
1615     m_aBoxLoseFocusIdle.Start();
1616 }
1617 
IMPL_LINK_NOARG(CustomPropertyLine,BoxLoseFocusHdl,weld::Widget &,void)1618 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1619 {
1620     m_pParent->BoxLoseFocus(this);
1621 }
1622 
IMPL_LINK_NOARG(CustomPropertiesWindow,EditTimeoutHdl,Timer *,void)1623 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1624 {
1625     ValidateLine( m_pCurrentLine, false );
1626 }
1627 
IMPL_LINK_NOARG(CustomPropertiesWindow,BoxTimeoutHdl,Timer *,void)1628 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1629 {
1630     ValidateLine( m_pCurrentLine, true );
1631 }
1632 
IsLineValid(CustomPropertyLine * pLine) const1633 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1634 {
1635     bool bIsValid = true;
1636     pLine->m_bTypeLostFocus = false;
1637     auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1638     OUString sValue = pLine->m_xValueEdit->get_text();
1639     if ( sValue.isEmpty() )
1640         return true;
1641 
1642     sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1643     if ( Custom_Type_Number == nType )
1644         // tdf#116214 Scientific format allows to use also standard numbers
1645         nIndex = const_cast< SvNumberFormatter& >(
1646             m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1647     else if ( Custom_Type_Date == nType )
1648         nIndex = const_cast< SvNumberFormatter& >(
1649             m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1650 
1651     if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1652     {
1653         sal_uInt32 nTemp = nIndex;
1654         double fDummy = 0.0;
1655         bIsValid = const_cast< SvNumberFormatter& >(
1656             m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1657         if ( bIsValid && nTemp != nIndex )
1658             // sValue is a number but the format doesn't match the index
1659             bIsValid = false;
1660     }
1661 
1662     return bIsValid;
1663 }
1664 
ValidateLine(CustomPropertyLine * pLine,bool bIsFromTypeBox)1665 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1666 {
1667     if (pLine && !IsLineValid(pLine))
1668     {
1669         if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1670             pLine->m_bTypeLostFocus = true;
1671         std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1672                                                          VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1673         if (xMessageBox->run() == RET_OK)
1674             pLine->m_xTypeBox->set_active_id(OUString::number(Custom_Type_Text));
1675         else
1676             pLine->m_xValueEdit->grab_focus();
1677     }
1678 }
1679 
SetVisibleLineCount(sal_uInt32 nCount)1680 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1681 {
1682     while (GetExistingLineCount() < nCount)
1683     {
1684         CreateNewLine();
1685     }
1686 }
1687 
AddLine(const OUString & sName,Any const & rAny)1688 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1689 {
1690     m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1691     ReloadLinesContent();
1692 }
1693 
CreateNewLine()1694 void CustomPropertiesWindow::CreateNewLine()
1695 {
1696     CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1697     pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1698     pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1699     pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1700 
1701     m_aCustomPropertiesLines.emplace_back( pNewLine );
1702 
1703     // this breaks online's jsdialogbuilder
1704     if (!comphelper::LibreOfficeKit::isActive()){
1705         // for ui-testing. Distinguish the elements in the lines
1706         sal_uInt16 nSize = m_aCustomPropertiesLines.size();
1707         pNewLine->m_xNameBox->set_buildable_name(
1708             pNewLine->m_xNameBox->get_buildable_name() + OUString::number(nSize));
1709         pNewLine->m_xTypeBox->set_buildable_name(
1710             pNewLine->m_xTypeBox->get_buildable_name() + OUString::number(nSize));
1711         pNewLine->m_xValueEdit->set_buildable_name(
1712             pNewLine->m_xValueEdit->get_buildable_name() + OUString::number(nSize));
1713         pNewLine->m_xRemoveButton->set_buildable_name(
1714             pNewLine->m_xRemoveButton->get_buildable_name() + OUString::number(nSize));
1715     }
1716 
1717     pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1718 }
1719 
AreAllLinesValid() const1720 bool CustomPropertiesWindow::AreAllLinesValid() const
1721 {
1722     bool bRet = true;
1723     for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1724     {
1725         if ( !IsLineValid( pLine.get() ) )
1726         {
1727             bRet = false;
1728             break;
1729         }
1730     }
1731 
1732     return bRet;
1733 }
1734 
ClearAllLines()1735 void CustomPropertiesWindow::ClearAllLines()
1736 {
1737     for (auto& pLine : m_aCustomPropertiesLines)
1738     {
1739         pLine->Clear();
1740     }
1741     m_pCurrentLine = nullptr;
1742     m_aCustomProperties.clear();
1743     m_nScrollPos = 0;
1744 }
1745 
DoScroll(sal_Int32 nNewPos)1746 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1747 {
1748     StoreCustomProperties();
1749     m_nScrollPos += nNewPos;
1750     ReloadLinesContent();
1751 }
1752 
GetCustomProperties()1753 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1754 {
1755     StoreCustomProperties();
1756 
1757     Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1758     std::transform(
1759         m_aCustomProperties.begin(), m_aCustomProperties.end(), aPropertiesSeq.getArray(),
1760         [](const auto& el) { return comphelper::makePropertyValue(el->m_sName, el->m_aValue); });
1761 
1762     return aPropertiesSeq;
1763 }
1764 
CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)1765 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1766     : m_xTimeField(std::move(xTimeField))
1767     , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1768     , m_isUTC(false)
1769 {
1770     m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1771     m_xFormatter->EnableEmptyField(false);
1772 }
1773 
get_value() const1774 tools::Time CustomPropertiesTimeField::get_value() const
1775 {
1776     return m_xFormatter->GetTime();
1777 }
1778 
set_value(const tools::Time & rTime)1779 void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1780 {
1781     m_xFormatter->SetTime(rTime);
1782 }
1783 
~CustomPropertiesTimeField()1784 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1785 {
1786 }
1787 
CustomPropertiesDateField(SvtCalendarBox * pDateField)1788 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1789     : m_xDateField(pDateField)
1790 {
1791     DateTime aDateTime(DateTime::SYSTEM);
1792     m_xDateField->set_date(aDateTime);
1793 }
1794 
set_visible(bool bVisible)1795 void CustomPropertiesDateField::set_visible(bool bVisible)
1796 {
1797     m_xDateField->set_visible(bVisible);
1798 }
1799 
get_date() const1800 Date CustomPropertiesDateField::get_date() const
1801 {
1802     return m_xDateField->get_date();
1803 }
1804 
set_date(const Date & rDate)1805 void CustomPropertiesDateField::set_date(const Date& rDate)
1806 {
1807     m_xDateField->set_date(rDate);
1808 }
1809 
~CustomPropertiesDateField()1810 CustomPropertiesDateField::~CustomPropertiesDateField()
1811 {
1812 }
1813 
StoreCustomProperties()1814 void CustomPropertiesWindow::StoreCustomProperties()
1815 {
1816     sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1817 
1818     for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1819     {
1820         CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1821 
1822         OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1823         if (!sPropertyName.isEmpty())
1824         {
1825             m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1826             auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1827             if (Custom_Type_Number == nType)
1828             {
1829                 double nValue = 0;
1830                 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1831                 bool bIsNum = m_aNumberFormatter.
1832                     IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1833                 if (bIsNum)
1834                     m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1835             }
1836             else if (Custom_Type_Boolean == nType)
1837             {
1838                 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1839                 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1840             }
1841             else if (Custom_Type_Datetime == nType)
1842             {
1843                 Date aTmpDate = pLine->m_xDateField->get_date();
1844                 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1845                 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1846                     aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1847                     aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1848                     pLine->m_xTimeField->m_isUTC);
1849                 if (pLine->m_xDateField->m_TZ)
1850                 {
1851                     m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1852                         aDateTime, *pLine->m_xDateField->m_TZ);
1853                 }
1854                 else
1855                 {
1856                     m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1857                 }
1858             }
1859             else if (Custom_Type_Date == nType)
1860             {
1861                 Date aTmpDate = pLine->m_xDateField->get_date();
1862                 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1863                     aTmpDate.GetYear());
1864                 if (pLine->m_xDateField->m_TZ)
1865                 {
1866                     m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1867                         aDate, *pLine->m_xDateField->m_TZ);
1868                 }
1869                 else
1870                 {
1871                     m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1872                 }
1873             }
1874             else if (Custom_Type_Duration == nType)
1875             {
1876                 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1877             }
1878             else
1879             {
1880                 OUString sValue(pLine->m_xValueEdit->get_text());
1881                 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1882             }
1883         }
1884     }
1885 }
1886 
SetCustomProperties(std::vector<std::unique_ptr<CustomProperty>> && rProperties)1887 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1888 {
1889     m_aCustomProperties = std::move(rProperties);
1890     ReloadLinesContent();
1891 }
1892 
ReloadLinesContent()1893 void CustomPropertiesWindow::ReloadLinesContent()
1894 {
1895     double nTmpValue = 0;
1896     bool bTmpValue = false;
1897     OUString sTmpValue;
1898     util::DateTime aTmpDateTime;
1899     util::Date aTmpDate;
1900     util::DateTimeWithTimezone aTmpDateTimeTZ;
1901     util::DateWithTimezone aTmpDateTZ;
1902     util::Duration aTmpDuration;
1903     SvtSysLocale aSysLocale;
1904     const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1905     CustomProperties nType = Custom_Type_Unknown;
1906     OUString sValue;
1907 
1908     sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1909     sal_uInt32 i = 0;
1910 
1911     for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1912     {
1913         const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1914         const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1915 
1916         CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1917         pLine->Clear();
1918 
1919         pLine->m_xNameBox->set_entry_text(rName);
1920         pLine->m_xLine->show();
1921 
1922         if (!rAny.hasValue())
1923         {
1924             pLine->m_xValueEdit->set_text(OUString());
1925         }
1926         else if (rAny >>= nTmpValue)
1927         {
1928             sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1929             sValue = m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex);
1930             pLine->m_xValueEdit->set_text(sValue);
1931             nType = Custom_Type_Number;
1932         }
1933         else if (rAny >>= bTmpValue)
1934         {
1935             sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1936             nType = Custom_Type_Boolean;
1937         }
1938         else if (rAny >>= sTmpValue)
1939         {
1940             pLine->m_xValueEdit->set_text(sTmpValue);
1941             nType = Custom_Type_Text;
1942         }
1943         else if (rAny >>= aTmpDate)
1944         {
1945             pLine->m_xDateField->set_date(Date(aTmpDate));
1946             nType = Custom_Type_Date;
1947         }
1948         else if (rAny >>= aTmpDateTime)
1949         {
1950             pLine->m_xDateField->set_date(Date(aTmpDateTime));
1951             pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1952             pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1953             nType = Custom_Type_Datetime;
1954         }
1955         else if (rAny >>= aTmpDateTZ)
1956         {
1957             pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1958                 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1959             pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1960             nType = Custom_Type_Date;
1961         }
1962 
1963         else if (rAny >>= aTmpDateTimeTZ)
1964         {
1965             util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1966             pLine->m_xDateField->set_date(Date(rDT));
1967             pLine->m_xTimeField->set_value(tools::Time(rDT));
1968             pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1969             pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1970             nType = Custom_Type_Datetime;
1971         }
1972         else if (rAny >>= aTmpDuration)
1973         {
1974             nType = Custom_Type_Duration;
1975             pLine->m_xDurationField->SetDuration(aTmpDuration);
1976         }
1977 
1978         if (Custom_Type_Boolean == nType)
1979         {
1980             if (bTmpValue)
1981                 pLine->m_xYesNoButton->CheckYes();
1982             else
1983                 pLine->m_xYesNoButton->CheckNo();
1984         }
1985         pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1986 
1987         pLine->DoTypeHdl(*pLine->m_xTypeBox);
1988     }
1989 
1990     // tdf#132667 - grab focus on the last inserted property
1991     if (i > 0 && m_aCustomProperties[nDataModelPos + i - 1]->m_sName.isEmpty())
1992     {
1993         CustomPropertyLine* pLine = m_aCustomPropertiesLines[i - 1].get();
1994         pLine->m_xNameBox->grab_focus();
1995     }
1996 
1997     while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1998     {
1999         CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
2000         pLine->Hide();
2001         i++;
2002     }
2003 }
2004 
CustomPropertiesControl()2005 CustomPropertiesControl::CustomPropertiesControl()
2006     : m_nThumbPos(0)
2007 {
2008 }
2009 
Init(weld::Builder & rBuilder)2010 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
2011 {
2012     m_xBox = rBuilder.weld_widget(u"box"_ustr);
2013     m_xBody = rBuilder.weld_container(u"properties"_ustr);
2014 
2015     m_xName = rBuilder.weld_label(u"name"_ustr);
2016     m_xType = rBuilder.weld_label(u"type"_ustr);
2017     m_xValue = rBuilder.weld_label(u"value"_ustr);
2018     m_xVertScroll = rBuilder.weld_scrolled_window(u"scroll"_ustr, true);
2019     m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
2020 
2021     m_xBox->set_stack_background();
2022     m_xVertScroll->show();
2023 
2024     std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
2025     Size aLineSize(xNewLine->m_xLine->get_preferred_size());
2026     m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
2027     m_xBody->set_size_request(aLineSize.Width() + 6, -1);
2028     auto nHeight = aLineSize.Height() * 8;
2029     m_xVertScroll->set_size_request(-1, nHeight + 6);
2030 
2031     m_xPropertiesWin->SetHeight(nHeight);
2032     m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
2033 
2034     m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
2035     m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
2036     m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
2037 
2038     m_xBody->move(xNewLine->m_xLine.get(), nullptr);
2039     xNewLine.reset();
2040 
2041     m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
2042 
2043     m_xVertScroll->vadjustment_set_upper(0);
2044     m_xVertScroll->vadjustment_set_page_size(0xFFFF);
2045 
2046     Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
2047     m_xVertScroll->connect_vadjustment_value_changed(aScrollLink);
2048 
2049     ResizeHdl(Size(-1, nHeight));
2050 }
2051 
IMPL_LINK(CustomPropertiesControl,ResizeHdl,const Size &,rSize,void)2052 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
2053 {
2054     int nHeight = rSize.Height() - 6;
2055     if (nHeight == m_xPropertiesWin->GetHeight())
2056         return;
2057     m_xPropertiesWin->SetHeight(nHeight);
2058     sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
2059     sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
2060     m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
2061     m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
2062     m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
2063     m_xPropertiesWin->ReloadLinesContent();
2064 }
2065 
~CustomPropertiesControl()2066 CustomPropertiesControl::~CustomPropertiesControl()
2067 {
2068 }
2069 
IMPL_LINK(CustomPropertiesControl,ScrollHdl,weld::ScrolledWindow &,rScrollBar,void)2070 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
2071 {
2072     sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
2073     int nThumbPos = rScrollBar.vadjustment_get_value();
2074     nOffset *= ( m_nThumbPos - nThumbPos );
2075     m_nThumbPos = nThumbPos;
2076     m_xPropertiesWin->DoScroll( nOffset );
2077 }
2078 
IMPL_LINK_NOARG(CustomPropertiesControl,RemovedHdl,void *,void)2079 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
2080 {
2081     auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2082     m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2083     if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
2084     {
2085         m_xVertScroll->vadjustment_set_value(nLineCount - 1);
2086         ScrollHdl(*m_xVertScroll);
2087     }
2088 }
2089 
AddLine(Any const & rAny)2090 void CustomPropertiesControl::AddLine( Any const & rAny )
2091 {
2092     m_xPropertiesWin->AddLine( OUString(), rAny );
2093     auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2094     m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2095     if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
2096     {
2097         m_xVertScroll->vadjustment_set_value(nLineCount + 1);
2098         ScrollHdl(*m_xVertScroll);
2099     }
2100 }
2101 
SetCustomProperties(std::vector<std::unique_ptr<CustomProperty>> && rProperties)2102 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
2103 {
2104     m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
2105     auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2106     m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2107 }
2108 
2109 // class SfxCustomPropertiesPage -----------------------------------------
SfxCustomPropertiesPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)2110 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
2111     : SfxTabPage(pPage, pController, u"sfx/ui/custominfopage.ui"_ustr, u"CustomInfoPage"_ustr, &rItemSet)
2112     , m_xPropertiesCtrl(new CustomPropertiesControl)
2113     , m_xAdd(m_xBuilder->weld_button(u"add"_ustr))
2114 {
2115     m_xPropertiesCtrl->Init(*m_xBuilder);
2116     m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
2117 }
2118 
~SfxCustomPropertiesPage()2119 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
2120 {
2121     m_xPropertiesCtrl.reset();
2122 }
2123 
IMPL_LINK_NOARG(SfxCustomPropertiesPage,AddHdl,weld::Button &,void)2124 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
2125 {
2126     // tdf#115853: reload current lines before adding a brand new one
2127     // indeed the info are deleted by ClearCustomProperties
2128     // each time SfxDocumentInfoItem destructor is called
2129     SfxDocumentInfoItem pInfo;
2130     const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2131     for ( const auto& rProperty : aPropertySeq )
2132     {
2133         if ( !rProperty.Name.isEmpty() )
2134         {
2135             pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
2136         }
2137     }
2138 
2139     Any aAny;
2140     m_xPropertiesCtrl->AddLine(aAny);
2141 }
2142 
FillItemSet(SfxItemSet * rSet)2143 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
2144 {
2145     const SfxDocumentInfoItem* pItem = nullptr;
2146     SfxDocumentInfoItem* pInfo = nullptr;
2147     bool bMustDelete = false;
2148 
2149     if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2150     {
2151         pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2152         if (!pItem)
2153             pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2154         else
2155         {
2156             bMustDelete = true;
2157             pInfo = new SfxDocumentInfoItem( *pItem );
2158         }
2159     }
2160 
2161     if ( pInfo )
2162     {
2163         // If it's a CMIS document, we can't save custom properties
2164         if ( pInfo->isCmisDocument( ) )
2165         {
2166             if ( bMustDelete )
2167                 delete pInfo;
2168             return false;
2169         }
2170 
2171         pInfo->ClearCustomProperties();
2172         const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2173         for ( const auto& rProperty : aPropertySeq )
2174         {
2175             if ( !rProperty.Name.isEmpty() )
2176                 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
2177         }
2178     }
2179 
2180     if (pInfo)
2181     {
2182         rSet->Put(*pInfo);
2183         if ( bMustDelete )
2184             delete pInfo;
2185     }
2186     return true;
2187 }
2188 
Reset(const SfxItemSet * rItemSet)2189 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
2190 {
2191     m_xPropertiesCtrl->ClearAllLines();
2192     const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2193     std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
2194     // tdf#123919 - sort custom document properties
2195     auto const sort = comphelper::string::NaturalStringSorter(
2196         comphelper::getProcessComponentContext(),
2197         Application::GetSettings().GetLanguageTag().getLocale());
2198     std::sort(aCustomProps.begin(), aCustomProps.end(),
2199               [&sort](const std::unique_ptr<CustomProperty>& rLHS,
2200                       const std::unique_ptr<CustomProperty>& rRHS) {
2201                   return sort.compare(rLHS->m_sName, rRHS->m_sName) < 0;
2202               });
2203     m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
2204 }
2205 
DeactivatePage(SfxItemSet *)2206 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2207 {
2208     DeactivateRC nRet = DeactivateRC::LeavePage;
2209     if ( !m_xPropertiesCtrl->AreAllLinesValid() )
2210         nRet = DeactivateRC::KeepPage;
2211     return nRet;
2212 }
2213 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)2214 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2215 {
2216     return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
2217 }
2218 
CmisValue(weld::Widget * pParent,const OUString & aStr)2219 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
2220     : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2221     , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2222     , m_xValueEdit(m_xBuilder->weld_entry(u"value"_ustr))
2223 {
2224     m_xValueEdit->show();
2225     m_xValueEdit->set_text(aStr);
2226 }
2227 
CmisDateTime(weld::Widget * pParent,const util::DateTime & aDateTime)2228 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
2229     : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2230     , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2231     , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr)))
2232     , m_xTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr))
2233     , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
2234 {
2235     m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
2236     m_xFormatter->EnableEmptyField(false);
2237 
2238     m_xDateField->show();
2239     m_xTimeField->show();
2240     m_xDateField->set_date(Date(aDateTime));
2241     m_xFormatter->SetTime(tools::Time(aDateTime));
2242 }
2243 
CmisYesNo(weld::Widget * pParent,bool bValue)2244 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
2245     : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2246     , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2247     , m_xYesButton(m_xBuilder->weld_radio_button(u"yes"_ustr))
2248     , m_xNoButton(m_xBuilder->weld_radio_button(u"no"_ustr))
2249 {
2250     m_xYesButton->show();
2251     m_xNoButton->show();
2252     if (bValue)
2253         m_xYesButton->set_active(true);
2254     else
2255         m_xNoButton->set_active(true);
2256 }
2257 
2258 // struct CmisPropertyLine ---------------------------------------------
CmisPropertyLine(weld::Widget * pParent)2259 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2260     : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2261     , m_sType(CMIS_TYPE_STRING)
2262     , m_bUpdatable(false)
2263     , m_bRequired(false)
2264     , m_bMultiValued(false)
2265     , m_bOpenChoice(false)
2266     , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2267     , m_xName(m_xBuilder->weld_label(u"name"_ustr))
2268     , m_xType(m_xBuilder->weld_label(u"type"_ustr))
2269 {
2270     m_xFrame->set_sensitive(true);
2271 }
2272 
~CmisPropertyLine()2273 CmisPropertyLine::~CmisPropertyLine( )
2274 {
2275 }
2276 
2277 // class CmisPropertiesWindow -----------------------------------------
2278 
CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)2279 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2280     : m_xBox(std::move(xParent))
2281     , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2282                          Application::GetSettings().GetLanguageTag().getLanguageType())
2283 {
2284 }
2285 
~CmisPropertiesWindow()2286 CmisPropertiesWindow::~CmisPropertiesWindow()
2287 {
2288 }
2289 
ClearAllLines()2290 void CmisPropertiesWindow::ClearAllLines()
2291 {
2292     m_aCmisPropertiesLines.clear();
2293 }
2294 
AddLine(const OUString & sId,const OUString & sName,const OUString & sType,const bool bUpdatable,const bool bRequired,const bool bMultiValued,const bool bOpenChoice,Any &,Any const & rAny)2295 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2296                                     const OUString& sType, const bool bUpdatable,
2297                                     const bool bRequired, const bool bMultiValued,
2298                                     const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2299 {
2300     std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2301 
2302     pNewLine->m_sId = sId;
2303     pNewLine->m_sType = sType;
2304     pNewLine->m_bUpdatable = bUpdatable;
2305     pNewLine->m_bRequired = bRequired;
2306     pNewLine->m_bMultiValued = bMultiValued;
2307     pNewLine->m_bOpenChoice = bOpenChoice;
2308 
2309     if ( sType == CMIS_TYPE_INTEGER )
2310     {
2311         Sequence< sal_Int64 > seqValue;
2312         rAny >>= seqValue;
2313         sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2314         for (const auto& rValue : seqValue)
2315         {
2316             OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2317             std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2318             pValue->m_xValueEdit->set_editable(bUpdatable);
2319             pNewLine->m_aValues.push_back( std::move(pValue) );
2320         }
2321     }
2322     else if ( sType == CMIS_TYPE_DECIMAL )
2323     {
2324         Sequence< double > seqValue;
2325         rAny >>= seqValue;
2326         sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2327         for (const auto& rValue : seqValue)
2328         {
2329             OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2330             std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2331             pValue->m_xValueEdit->set_editable(bUpdatable);
2332             pNewLine->m_aValues.push_back( std::move(pValue) );
2333         }
2334 
2335     }
2336     else if ( sType == CMIS_TYPE_BOOL )
2337     {
2338         Sequence<sal_Bool> seqValue;
2339         rAny >>= seqValue;
2340         for (const auto& rValue : seqValue)
2341         {
2342             std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2343             pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2344             pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2345             pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2346         }
2347     }
2348     else if ( sType == CMIS_TYPE_STRING )
2349     {
2350         Sequence< OUString > seqValue;
2351         rAny >>= seqValue;
2352         for (const auto& rValue : seqValue)
2353         {
2354             std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2355             pValue->m_xValueEdit->set_editable(bUpdatable);
2356             pNewLine->m_aValues.push_back( std::move(pValue) );
2357         }
2358     }
2359     else if ( sType == CMIS_TYPE_DATETIME )
2360     {
2361         Sequence< util::DateTime > seqValue;
2362         rAny >>= seqValue;
2363         for (const auto& rValue : seqValue)
2364         {
2365             std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2366             pDateTime->m_xDateField->set_sensitive(bUpdatable);
2367             pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2368             pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2369         }
2370     }
2371     pNewLine->m_xName->set_label( sName );
2372     pNewLine->m_xName->show();
2373     pNewLine->m_xType->set_label( sType );
2374     pNewLine->m_xType->show();
2375 
2376     m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2377 }
2378 
GetCmisProperties() const2379 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2380 {
2381     Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2382     auto aPropertiesSeqRange = asNonConstRange(aPropertiesSeq);
2383     sal_Int32 i = 0;
2384     for ( auto& rxLine : m_aCmisPropertiesLines )
2385     {
2386         CmisPropertyLine* pLine = rxLine.get();
2387 
2388         aPropertiesSeqRange[i].Id = pLine->m_sId;
2389         aPropertiesSeqRange[i].Type = pLine->m_sType;
2390         aPropertiesSeqRange[i].Updatable = pLine->m_bUpdatable;
2391         aPropertiesSeqRange[i].Required = pLine->m_bRequired;
2392         aPropertiesSeqRange[i].OpenChoice = pLine->m_bOpenChoice;
2393         aPropertiesSeqRange[i].MultiValued = pLine->m_bMultiValued;
2394 
2395         OUString sPropertyName = pLine->m_xName->get_label();
2396         if ( !sPropertyName.isEmpty() )
2397         {
2398             aPropertiesSeqRange[i].Name = sPropertyName;
2399             OUString sType = pLine->m_xType->get_label();
2400             if ( CMIS_TYPE_DECIMAL == sType )
2401             {
2402                 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2403                     m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2404                 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2405                 auto seqValueRange = asNonConstRange(seqValue);
2406                 sal_Int32 k = 0;
2407                 for ( const auto& rxValue : pLine->m_aValues )
2408                 {
2409                     double dValue = 0.0;
2410                     OUString sValue( rxValue->m_xValueEdit->get_text() );
2411                     bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2412                     IsNumberFormat( sValue, nIndex, dValue );
2413                     if ( bIsNum )
2414                         seqValueRange[k] = dValue;
2415                     ++k;
2416                 }
2417                 aPropertiesSeqRange[i].Value <<= seqValue;
2418             }
2419             else if ( CMIS_TYPE_INTEGER == sType )
2420             {
2421                 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2422                     m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2423                 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2424                 auto seqValueRange = asNonConstRange(seqValue);
2425                 sal_Int32 k = 0;
2426                 for ( const auto& rxValue : pLine->m_aValues )
2427                 {
2428                     double dValue = 0;
2429                     OUString sValue( rxValue->m_xValueEdit->get_text() );
2430                     bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2431                     IsNumberFormat( sValue, nIndex, dValue );
2432                     if ( bIsNum )
2433                         seqValueRange[k] = static_cast<sal_Int64>(dValue);
2434                     ++k;
2435                 }
2436                 aPropertiesSeqRange[i].Value <<= seqValue;
2437             }
2438             else if ( CMIS_TYPE_BOOL == sType )
2439             {
2440                 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2441                 sal_Bool* pseqValue = seqValue.getArray();
2442                 sal_Int32 k = 0;
2443                 for ( const auto& rxYesNo : pLine->m_aYesNos )
2444                 {
2445                     bool bValue = rxYesNo->m_xYesButton->get_active();
2446                     pseqValue[k] = bValue;
2447                     ++k;
2448                 }
2449                 aPropertiesSeqRange[i].Value <<= seqValue;
2450 
2451             }
2452             else if ( CMIS_TYPE_DATETIME == sType )
2453             {
2454                 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2455                 auto seqValueRange = asNonConstRange(seqValue);
2456                 sal_Int32 k = 0;
2457                 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2458                 {
2459                     Date aTmpDate = rxDateTime->m_xDateField->get_date();
2460                     tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2461                     util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2462                                               aTmpTime.GetMin(), aTmpTime.GetHour(),
2463                                               aTmpDate.GetDay(), aTmpDate.GetMonth(),
2464                                               aTmpDate.GetYear(), true );
2465                     seqValueRange[k] = aDateTime;
2466                     ++k;
2467                 }
2468                 aPropertiesSeqRange[i].Value <<= seqValue;
2469             }
2470             else
2471             {
2472                 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2473                 auto seqValueRange = asNonConstRange(seqValue);
2474                 sal_Int32 k = 0;
2475                 for ( const auto& rxValue : pLine->m_aValues )
2476                 {
2477                     seqValueRange[k] = rxValue->m_xValueEdit->get_text();
2478                     ++k;
2479                 }
2480                 aPropertiesSeqRange[i].Value <<= seqValue;
2481             }
2482         }
2483         ++i;
2484     }
2485 
2486     return aPropertiesSeq;
2487 }
2488 
CmisPropertiesControl(weld::Builder & rBuilder)2489 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2490     : m_aPropertiesWin(rBuilder.weld_container(u"CmisWindow"_ustr))
2491     , m_xScrolledWindow(rBuilder.weld_scrolled_window(u"CmisScroll"_ustr))
2492 {
2493     // set height to something small and force it to take the size
2494     // dictated by the other pages
2495     m_xScrolledWindow->set_size_request(-1, 42);
2496 }
2497 
ClearAllLines()2498 void CmisPropertiesControl::ClearAllLines()
2499 {
2500    m_aPropertiesWin.ClearAllLines();
2501 }
2502 
AddLine(const OUString & sId,const OUString & sName,const OUString & sType,const bool bUpdatable,const bool bRequired,const bool bMultiValued,const bool bOpenChoice,Any & aChoices,Any const & rAny)2503 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2504                                      const OUString& sType, const bool bUpdatable,
2505                                      const bool bRequired, const bool bMultiValued,
2506                                      const bool bOpenChoice, Any& aChoices, Any const & rAny
2507                                      )
2508 {
2509     m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2510                                bOpenChoice, aChoices, rAny );
2511 }
2512 
2513 // class SfxCmisPropertiesPage -----------------------------------------
SfxCmisPropertiesPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)2514 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2515     : SfxTabPage(pPage, pController, u"sfx/ui/cmisinfopage.ui"_ustr, u"CmisInfoPage"_ustr, &rItemSet)
2516     , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2517 {
2518 }
2519 
~SfxCmisPropertiesPage()2520 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2521 {
2522     m_xPropertiesCtrl.reset();
2523 }
2524 
FillItemSet(SfxItemSet * rSet)2525 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2526 {
2527     const SfxDocumentInfoItem* pItem = nullptr;
2528     SfxDocumentInfoItem* pInfo = nullptr;
2529     bool bMustDelete = false;
2530 
2531     if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2532     {
2533         pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2534         if (!pItem)
2535             pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2536         else
2537         {
2538             bMustDelete = true;
2539             pInfo = new SfxDocumentInfoItem( *pItem );
2540         }
2541     }
2542 
2543     sal_Int32 modifiedNum = 0;
2544     if ( pInfo )
2545     {
2546         Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2547         Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2548 
2549         std::vector< document::CmisProperty > changedProps;
2550         for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2551         {
2552             if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2553             {
2554                 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2555                 {
2556                     Sequence< util::DateTime > oldValue;
2557                     aOldProps[i].Value >>= oldValue;
2558                     // We only edit hours and minutes
2559                     // don't compare NanoSeconds and Seconds
2560                     for ( auto& rDateTime : asNonConstRange(oldValue) )
2561                     {
2562                         rDateTime.NanoSeconds = 0;
2563                         rDateTime.Seconds = 0;
2564                     }
2565                     Sequence< util::DateTime > newValue;
2566                     aNewProps[i].Value >>= newValue;
2567                     if ( oldValue != newValue )
2568                     {
2569                         modifiedNum++;
2570                         changedProps.push_back( aNewProps[i] );
2571                     }
2572                 }
2573                 else if ( aOldProps[i].Value != aNewProps[i].Value )
2574                 {
2575                     modifiedNum++;
2576                     changedProps.push_back( aNewProps[i] );
2577                 }
2578             }
2579         }
2580         Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2581         pInfo->SetCmisProperties( aModifiedProps );
2582         rSet->Put( *pInfo );
2583         if ( bMustDelete )
2584             delete pInfo;
2585     }
2586 
2587     return modifiedNum;
2588 }
2589 
Reset(const SfxItemSet * rItemSet)2590 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2591 {
2592     m_xPropertiesCtrl->ClearAllLines();
2593     const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2594     uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2595     for ( auto& rCmisProp : asNonConstRange(aCmisProps) )
2596     {
2597         m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2598                                    rCmisProp.Name,
2599                                    rCmisProp.Type,
2600                                    rCmisProp.Updatable,
2601                                    rCmisProp.Required,
2602                                    rCmisProp.MultiValued,
2603                                    rCmisProp.OpenChoice,
2604                                    rCmisProp.Choices,
2605                                    rCmisProp.Value);
2606     }
2607 }
2608 
DeactivatePage(SfxItemSet *)2609 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2610 {
2611     return DeactivateRC::LeavePage;
2612 }
2613 
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)2614 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2615 {
2616     return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2617 }
2618 
2619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2620