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