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