nss: upgrade to release 3.73
[LibreOffice.git] / sfx2 / source / dialog / dinfdlg.cxx
blob6a7bd27aafaf5dfca7130f2bd2603a7f658ecd9a
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/eitem.hxx>
21 #include <tools/datetime.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/urlobj.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/weld.hxx>
26 #include <vcl/weldutils.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/ctrlbox.hxx>
34 #include <svtools/imagemgr.hxx>
35 #include <sal/log.hxx>
36 #include <osl/diagnose.h>
38 #include <memory>
40 #include <comphelper/sequence.hxx>
41 #include <comphelper/string.hxx>
42 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
43 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
44 #include <unotools/syslocale.hxx>
45 #include <rtl/math.hxx>
46 #include <com/sun/star/beans/PropertyAttribute.hpp>
47 #include <com/sun/star/beans/XPropertyContainer.hpp>
48 #include <com/sun/star/beans/XPropertySet.hpp>
49 #include <com/sun/star/util/DateTime.hpp>
50 #include <com/sun/star/util/Date.hpp>
51 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
52 #include <com/sun/star/util/DateWithTimezone.hpp>
53 #include <com/sun/star/util/Duration.hpp>
54 #include <com/sun/star/document/XDocumentProperties.hpp>
55 #include <com/sun/star/document/CmisProperty.hpp>
57 #include <vcl/timer.hxx>
58 #include <vcl/settings.hxx>
59 #include <sfx2/sfxresid.hxx>
60 #include <sfx2/frame.hxx>
61 #include <sfx2/filedlghelper.hxx>
62 #include <sfx2/dinfdlg.hxx>
63 #include <sfx2/sfxsids.hrc>
64 #include <helper.hxx>
65 #include <sfx2/objsh.hxx>
66 #include <sfx2/docfile.hxx>
68 #include <documentfontsdialog.hxx>
69 #include <dinfdlg.hrc>
70 #include <sfx2/strings.hrc>
71 #include <strings.hxx>
72 #include <tools/diagnose_ex.h>
73 #include "securitypage.hxx"
75 #include <algorithm>
77 using namespace ::com::sun::star;
78 using namespace ::com::sun::star::lang;
79 using namespace ::com::sun::star::ui::dialogs;
80 using namespace ::com::sun::star::uno;
82 struct CustomProperty
84 OUString m_sName;
85 css::uno::Any m_aValue;
87 CustomProperty( const OUString& sName, const css::uno::Any& rValue ) :
88 m_sName( sName ), m_aValue( rValue ) {}
91 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
93 namespace {
95 OUString CreateSizeText( sal_Int64 nSize )
97 OUString aUnitStr = " " + SfxResId(STR_BYTES);
98 sal_Int64 nSize1 = nSize;
99 sal_Int64 nSize2 = nSize1;
100 sal_Int64 nMega = 1024 * 1024;
101 sal_Int64 nGiga = nMega * 1024;
102 double fSize = nSize;
103 int nDec = 0;
105 if ( nSize1 >= 10000 && nSize1 < nMega )
107 nSize1 /= 1024;
108 aUnitStr = " " + SfxResId(STR_KB);
109 fSize /= 1024;
110 nDec = 0;
112 else if ( nSize1 >= nMega && nSize1 < nGiga )
114 nSize1 /= nMega;
115 aUnitStr = " " + SfxResId(STR_MB);
116 fSize /= nMega;
117 nDec = 2;
119 else if ( nSize1 >= nGiga )
121 nSize1 /= nGiga;
122 aUnitStr = " " + SfxResId(STR_GB);
123 fSize /= nGiga;
124 nDec = 3;
126 const SvtSysLocale aSysLocale;
127 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
128 OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
129 if ( nSize1 < nSize2 )
131 aSizeStr = ::rtl::math::doubleToUString( fSize,
132 rtl_math_StringFormat_F, nDec,
133 rLocaleWrapper.getNumDecimalSep()[0] )
134 + aUnitStr
135 + " ("
136 + rLocaleWrapper.getNum( nSize2, 0 )
137 + " "
138 + SfxResId(STR_BYTES)
139 + ")";
141 return aSizeStr;
144 OUString ConvertDateTime_Impl( const OUString& rName,
145 const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
147 Date aD(uDT);
148 tools::Time aT(uDT);
149 const OUString aDelim( ", " );
150 OUString aStr = rWrapper.getDate( aD )
151 + aDelim
152 + rWrapper.getTime( aT );
153 OUString aAuthor = comphelper::string::stripStart(rName, ' ');
154 if (!aAuthor.isEmpty())
156 aStr += aDelim + aAuthor;
158 return aStr;
164 SfxDocumentInfoItem::SfxDocumentInfoItem()
165 : SfxStringItem()
166 , m_AutoloadDelay(0)
167 , m_AutoloadURL()
168 , m_isAutoloadEnabled(false)
169 , m_DefaultTarget()
170 , m_TemplateName()
171 , m_Author()
172 , m_CreationDate()
173 , m_ModifiedBy()
174 , m_ModificationDate()
175 , m_PrintedBy()
176 , m_PrintDate()
177 , m_EditingCycles(0)
178 , m_EditingDuration(0)
179 , m_Description()
180 , m_Keywords()
181 , m_Subject()
182 , m_Title()
183 , m_bHasTemplate( true )
184 , m_bDeleteUserData( false )
185 , m_bUseUserData( true )
186 , m_bUseThumbnailSave( true )
190 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
191 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
192 const uno::Sequence<document::CmisProperty>& i_cmisProps,
193 bool bIs, bool _bIs )
194 : SfxStringItem( SID_DOCINFO, rFile )
195 , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
196 , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
197 , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
198 , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
199 , m_TemplateName( i_xDocProps->getTemplateName() )
200 , m_Author( i_xDocProps->getAuthor() )
201 , m_CreationDate( i_xDocProps->getCreationDate() )
202 , m_ModifiedBy( i_xDocProps->getModifiedBy() )
203 , m_ModificationDate( i_xDocProps->getModificationDate() )
204 , m_PrintedBy( i_xDocProps->getPrintedBy() )
205 , m_PrintDate( i_xDocProps->getPrintDate() )
206 , m_EditingCycles( i_xDocProps->getEditingCycles() )
207 , m_EditingDuration( i_xDocProps->getEditingDuration() )
208 , m_Description( i_xDocProps->getDescription() )
209 , m_Keywords( ::comphelper::string::convertCommaSeparated(
210 i_xDocProps->getKeywords()) )
211 , m_Subject( i_xDocProps->getSubject() )
212 , m_Title( i_xDocProps->getTitle() )
213 , m_bHasTemplate( true )
214 , m_bDeleteUserData( false )
215 , m_bUseUserData( bIs )
216 , m_bUseThumbnailSave( _bIs )
220 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
221 if ( xContainer.is() )
223 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
224 const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
225 for ( const beans::Property& rProp : lProps )
227 // "fix" property? => not a custom property => ignore it!
228 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
230 SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
231 continue;
234 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
235 std::unique_ptr<CustomProperty> pProp(new CustomProperty( rProp.Name, aValue ));
236 m_aCustomProperties.push_back( std::move(pProp) );
240 // get CMIS properties
241 m_aCmisProperties = i_cmisProps;
243 catch ( Exception& ) {}
247 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
248 : SfxStringItem( rItem )
249 , m_AutoloadDelay( rItem.getAutoloadDelay() )
250 , m_AutoloadURL( rItem.getAutoloadURL() )
251 , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
252 , m_DefaultTarget( rItem.getDefaultTarget() )
253 , m_TemplateName( rItem.getTemplateName() )
254 , m_Author( rItem.getAuthor() )
255 , m_CreationDate( rItem.getCreationDate() )
256 , m_ModifiedBy( rItem.getModifiedBy() )
257 , m_ModificationDate( rItem.getModificationDate() )
258 , m_PrintedBy( rItem.getPrintedBy() )
259 , m_PrintDate( rItem.getPrintDate() )
260 , m_EditingCycles( rItem.getEditingCycles() )
261 , m_EditingDuration( rItem.getEditingDuration() )
262 , m_Description( rItem.getDescription() )
263 , m_Keywords( rItem.getKeywords() )
264 , m_Subject( rItem.getSubject() )
265 , m_Title( rItem.getTitle() )
266 , m_bHasTemplate( rItem.m_bHasTemplate )
267 , m_bDeleteUserData( rItem.m_bDeleteUserData )
268 , m_bUseUserData( rItem.m_bUseUserData )
269 , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
271 for (auto const & pOtherProp : rItem.m_aCustomProperties)
273 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
274 pOtherProp->m_aValue ));
275 m_aCustomProperties.push_back( std::move(pProp) );
278 m_aCmisProperties = rItem.m_aCmisProperties;
281 SfxDocumentInfoItem::~SfxDocumentInfoItem()
283 ClearCustomProperties();
286 SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
288 return new SfxDocumentInfoItem( *this );
291 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
293 if (!SfxStringItem::operator==(rItem))
294 return false;
295 const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
297 return
298 m_AutoloadDelay == rInfoItem.m_AutoloadDelay &&
299 m_AutoloadURL == rInfoItem.m_AutoloadURL &&
300 m_isAutoloadEnabled == rInfoItem.m_isAutoloadEnabled &&
301 m_DefaultTarget == rInfoItem.m_DefaultTarget &&
302 m_Author == rInfoItem.m_Author &&
303 m_CreationDate == rInfoItem.m_CreationDate &&
304 m_ModifiedBy == rInfoItem.m_ModifiedBy &&
305 m_ModificationDate == rInfoItem.m_ModificationDate &&
306 m_PrintedBy == rInfoItem.m_PrintedBy &&
307 m_PrintDate == rInfoItem.m_PrintDate &&
308 m_EditingCycles == rInfoItem.m_EditingCycles &&
309 m_EditingDuration == rInfoItem.m_EditingDuration &&
310 m_Description == rInfoItem.m_Description &&
311 m_Keywords == rInfoItem.m_Keywords &&
312 m_Subject == rInfoItem.m_Subject &&
313 m_Title == rInfoItem.m_Title &&
314 m_aCustomProperties.size() == rInfoItem.m_aCustomProperties.size() &&
315 std::equal(m_aCustomProperties.begin(), m_aCustomProperties.end(),
316 rInfoItem.m_aCustomProperties.begin()) &&
317 m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
321 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
323 m_Author = i_rAuthor;
324 DateTime now( DateTime::SYSTEM );
325 m_CreationDate = now.GetUNODateTime();
326 m_ModifiedBy = OUString();
327 m_PrintedBy = OUString();
328 m_ModificationDate = util::DateTime();
329 m_PrintDate = util::DateTime();
330 m_EditingDuration = 0;
331 m_EditingCycles = 1;
335 void SfxDocumentInfoItem::UpdateDocumentInfo(
336 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
337 bool i_bDoNotUpdateUserDefined) const
339 if (isAutoloadEnabled()) {
340 i_xDocProps->setAutoloadSecs(getAutoloadDelay());
341 i_xDocProps->setAutoloadURL(getAutoloadURL());
342 } else {
343 i_xDocProps->setAutoloadSecs(0);
344 i_xDocProps->setAutoloadURL(OUString());
346 i_xDocProps->setDefaultTarget(getDefaultTarget());
347 i_xDocProps->setAuthor(getAuthor());
348 i_xDocProps->setCreationDate(getCreationDate());
349 i_xDocProps->setModifiedBy(getModifiedBy());
350 i_xDocProps->setModificationDate(getModificationDate());
351 i_xDocProps->setPrintedBy(getPrintedBy());
352 i_xDocProps->setPrintDate(getPrintDate());
353 i_xDocProps->setEditingCycles(getEditingCycles());
354 i_xDocProps->setEditingDuration(getEditingDuration());
355 i_xDocProps->setDescription(getDescription());
356 i_xDocProps->setKeywords(
357 ::comphelper::string::convertCommaSeparated(getKeywords()));
358 i_xDocProps->setSubject(getSubject());
359 i_xDocProps->setTitle(getTitle());
361 // this is necessary in case of replaying a recorded macro:
362 // in this case, the macro may contain the 4 old user-defined DocumentInfo
363 // fields, but not any of the DocumentInfo properties;
364 // as a consequence, most of the UserDefined properties of the
365 // DocumentProperties would be summarily deleted here, which does not
366 // seem like a good idea.
367 if (i_bDoNotUpdateUserDefined)
368 return;
372 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
373 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
374 Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
375 const Sequence< beans::Property > lProps = xSetInfo->getProperties();
376 for ( const beans::Property& rProp : lProps )
378 if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
380 xContainer->removeProperty( rProp.Name );
384 for (auto const & pProp : m_aCustomProperties)
388 xContainer->addProperty( pProp->m_sName,
389 beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
391 catch ( Exception const & )
393 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
397 catch ( Exception const & )
399 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
404 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
406 m_bDeleteUserData = bSet;
410 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
412 m_bUseUserData = bSet;
415 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
417 m_bUseThumbnailSave = bSet;
420 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
422 std::vector< std::unique_ptr<CustomProperty> > aRet;
423 for (auto const & pOtherProp : m_aCustomProperties)
425 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
426 pOtherProp->m_aValue ));
427 aRet.push_back( std::move(pProp) );
430 return aRet;
433 void SfxDocumentInfoItem::ClearCustomProperties()
435 m_aCustomProperties.clear();
438 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
440 std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
441 m_aCustomProperties.push_back( std::move(pProp) );
445 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
447 m_aCmisProperties = cmisProps;
450 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
452 OUString aValue;
453 sal_Int32 nValue = 0;
454 bool bValue = false;
455 bool bIsInt = false;
456 bool bIsString = false;
457 nMemberId &= ~CONVERT_TWIPS;
458 switch ( nMemberId )
460 case MID_DOCINFO_USEUSERDATA:
461 bValue = IsUseUserData();
462 break;
463 case MID_DOCINFO_USETHUMBNAILSAVE:
464 bValue = IsUseThumbnailSave();
465 break;
466 case MID_DOCINFO_DELETEUSERDATA:
467 bValue = m_bDeleteUserData;
468 break;
469 case MID_DOCINFO_AUTOLOADENABLED:
470 bValue = isAutoloadEnabled();
471 break;
472 case MID_DOCINFO_AUTOLOADSECS:
473 bIsInt = true;
474 nValue = getAutoloadDelay();
475 break;
476 case MID_DOCINFO_AUTOLOADURL:
477 bIsString = true;
478 aValue = getAutoloadURL();
479 break;
480 case MID_DOCINFO_DEFAULTTARGET:
481 bIsString = true;
482 aValue = getDefaultTarget();
483 break;
484 case MID_DOCINFO_DESCRIPTION:
485 bIsString = true;
486 aValue = getDescription();
487 break;
488 case MID_DOCINFO_KEYWORDS:
489 bIsString = true;
490 aValue = getKeywords();
491 break;
492 case MID_DOCINFO_SUBJECT:
493 bIsString = true;
494 aValue = getSubject();
495 break;
496 case MID_DOCINFO_TITLE:
497 bIsString = true;
498 aValue = getTitle();
499 break;
500 default:
501 OSL_FAIL("Wrong MemberId!");
502 return false;
505 if ( bIsString )
506 rVal <<= aValue;
507 else if ( bIsInt )
508 rVal <<= nValue;
509 else
510 rVal <<= bValue;
511 return true;
514 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
516 OUString aValue;
517 sal_Int32 nValue=0;
518 bool bValue = false;
519 bool bRet = false;
520 nMemberId &= ~CONVERT_TWIPS;
521 switch ( nMemberId )
523 case MID_DOCINFO_USEUSERDATA:
524 bRet = (rVal >>= bValue);
525 if ( bRet )
526 SetUseUserData( bValue );
527 break;
528 case MID_DOCINFO_USETHUMBNAILSAVE:
529 bRet = (rVal >>=bValue);
530 if ( bRet )
531 SetUseThumbnailSave( bValue );
532 break;
533 case MID_DOCINFO_DELETEUSERDATA:
534 // QUESTION: deleting user data was done here; seems to be superfluous!
535 bRet = (rVal >>= bValue);
536 if ( bRet )
537 SetDeleteUserData( bValue );
538 break;
539 case MID_DOCINFO_AUTOLOADENABLED:
540 bRet = (rVal >>= bValue);
541 if ( bRet )
542 m_isAutoloadEnabled = bValue;
543 break;
544 case MID_DOCINFO_AUTOLOADSECS:
545 bRet = (rVal >>= nValue);
546 if ( bRet )
547 m_AutoloadDelay = nValue;
548 break;
549 case MID_DOCINFO_AUTOLOADURL:
550 bRet = (rVal >>= aValue);
551 if ( bRet )
552 m_AutoloadURL = aValue;
553 break;
554 case MID_DOCINFO_DEFAULTTARGET:
555 bRet = (rVal >>= aValue);
556 if ( bRet )
557 m_DefaultTarget = aValue;
558 break;
559 case MID_DOCINFO_DESCRIPTION:
560 bRet = (rVal >>= aValue);
561 if ( bRet )
562 setDescription(aValue);
563 break;
564 case MID_DOCINFO_KEYWORDS:
565 bRet = (rVal >>= aValue);
566 if ( bRet )
567 setKeywords(aValue);
568 break;
569 case MID_DOCINFO_SUBJECT:
570 bRet = (rVal >>= aValue);
571 if ( bRet )
572 setSubject(aValue);
573 break;
574 case MID_DOCINFO_TITLE:
575 bRet = (rVal >>= aValue);
576 if ( bRet )
577 setTitle(aValue);
578 break;
579 default:
580 OSL_FAIL("Wrong MemberId!");
581 return false;
584 return bRet;
587 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
588 : SfxTabPage(pPage, pController, "sfx/ui/descriptioninfopage.ui", "DescriptionInfoPage", &rItemSet)
589 , m_pInfoItem(nullptr)
590 , m_xTitleEd(m_xBuilder->weld_entry("title"))
591 , m_xThemaEd(m_xBuilder->weld_entry("subject"))
592 , m_xKeywordsEd(m_xBuilder->weld_entry("keywords"))
593 , m_xCommentEd(m_xBuilder->weld_text_view("comments"))
595 m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
596 m_xCommentEd->get_height_rows(16));
599 SfxDocumentDescPage::~SfxDocumentDescPage()
603 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
605 return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
608 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
610 // Test whether a change is present
611 const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
612 const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
613 const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
614 const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
615 if ( !( bTitleMod || bThemeMod || bKeywordsMod || bCommentMod ) )
617 return false;
620 // Generating the output data
621 const SfxPoolItem* pItem = nullptr;
622 SfxDocumentInfoItem* pInfo = nullptr;
623 const SfxItemSet* pExSet = GetDialogExampleSet();
625 if ( pExSet && SfxItemState::SET != pExSet->GetItemState( SID_DOCINFO, true, &pItem ) )
626 pInfo = m_pInfoItem;
627 else if ( pItem )
628 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem *>(pItem) );
630 if ( !pInfo )
632 SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
633 return false;
636 if ( bTitleMod )
638 pInfo->setTitle( m_xTitleEd->get_text() );
640 if ( bThemeMod )
642 pInfo->setSubject( m_xThemaEd->get_text() );
644 if ( bKeywordsMod )
646 pInfo->setKeywords( m_xKeywordsEd->get_text() );
648 if ( bCommentMod )
650 pInfo->setDescription( m_xCommentEd->get_text() );
652 rSet->Put( *pInfo );
653 if ( pInfo != m_pInfoItem )
655 delete pInfo;
658 return true;
661 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
663 m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
665 m_xTitleEd->set_text(m_pInfoItem->getTitle());
666 m_xThemaEd->set_text(m_pInfoItem->getSubject());
667 m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
668 m_xCommentEd->set_text(m_pInfoItem->getDescription());
670 m_xTitleEd->save_value();
671 m_xThemaEd->save_value();
672 m_xKeywordsEd->save_value();
673 m_xCommentEd->save_value();
675 const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
676 if (pROItem && pROItem->GetValue())
678 m_xTitleEd->set_editable(false);
679 m_xThemaEd->set_editable(false);
680 m_xKeywordsEd->set_editable(false);
681 m_xCommentEd->set_editable(false);
685 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
686 : SfxTabPage(pPage, pController, "sfx/ui/documentinfopage.ui", "DocumentInfoPage", &rItemSet)
687 , bEnableUseUserData( false )
688 , bHandleDelete( false )
689 , m_xBmp(m_xBuilder->weld_image("icon"))
690 , m_xNameED(m_xBuilder->weld_label("nameed"))
691 , m_xChangePassBtn(m_xBuilder->weld_button("changepass"))
692 , m_xShowTypeFT(m_xBuilder->weld_label("showtype"))
693 , m_xFileValEd(m_xBuilder->weld_label("showlocation"))
694 , m_xShowSizeFT(m_xBuilder->weld_label("showsize"))
695 , m_xCreateValFt(m_xBuilder->weld_label("showcreate"))
696 , m_xChangeValFt(m_xBuilder->weld_label("showmodify"))
697 , m_xSignedValFt(m_xBuilder->weld_label("showsigned"))
698 , m_xSignatureBtn(m_xBuilder->weld_button("signature"))
699 , m_xPrintValFt(m_xBuilder->weld_label("showprint"))
700 , m_xTimeLogValFt(m_xBuilder->weld_label("showedittime"))
701 , m_xDocNoValFt(m_xBuilder->weld_label("showrevision"))
702 , m_xUseUserDataCB(m_xBuilder->weld_check_button("userdatacb"))
703 , m_xDeleteBtn(m_xBuilder->weld_button("reset"))
704 , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button("thumbnailsavecb"))
705 , m_xTemplFt(m_xBuilder->weld_label("templateft"))
706 , m_xTemplValFt(m_xBuilder->weld_label("showtemplate"))
708 m_aUnknownSize = m_xShowSizeFT->get_label();
709 m_xShowSizeFT->set_label(OUString());
711 m_aMultiSignedStr = m_xSignedValFt->get_label();
712 m_xSignedValFt->set_label(OUString());
714 ImplUpdateSignatures();
715 ImplCheckPasswordState();
716 m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
717 m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
718 m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
720 // [i96288] Check if the document signature command is enabled
721 // on the main list enable/disable the pushbutton accordingly
722 SvtCommandOptions aCmdOptions;
723 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "Signature" ) )
724 m_xSignatureBtn->set_sensitive(false);
727 SfxDocumentPage::~SfxDocumentPage()
731 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
733 OUString aName;
734 if (bEnableUseUserData && m_xUseUserDataCB->get_active())
735 aName = SvtUserOptions().GetFullName();
736 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
737 DateTime now( DateTime::SYSTEM );
738 util::DateTime uDT( now.GetUNODateTime() );
739 m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
740 m_xChangeValFt->set_label( "" );
741 m_xPrintValFt->set_label( "" );
742 const tools::Time aTime( 0 );
743 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aTime ) );
744 m_xDocNoValFt->set_label(OUString('1'));
745 bHandleDelete = true;
748 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
750 SfxObjectShell* pDoc = SfxObjectShell::Current();
751 if( pDoc )
753 pDoc->SignDocumentContent(GetFrameWeld());
755 ImplUpdateSignatures();
759 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
761 SfxObjectShell* pShell = SfxObjectShell::Current();
764 if (!pShell)
765 break;
766 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
767 if (!pMedSet)
768 break;
769 std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
770 if (!pFilter)
771 break;
773 sfx2::RequestPassword(pFilter, OUString(), pMedSet, GetFrameWeld()->GetXWindow());
774 pShell->SetModified();
776 while (false);
779 void SfxDocumentPage::ImplUpdateSignatures()
781 SfxObjectShell* pDoc = SfxObjectShell::Current();
782 if ( !pDoc )
783 return;
785 SfxMedium* pMedium = pDoc->GetMedium();
786 if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
787 return;
789 Reference< security::XDocumentDigitalSignatures > xD;
792 xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
793 xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
795 catch ( const css::uno::DeploymentException& )
798 OUString s;
799 Sequence< security::DocumentSignatureInformation > aInfos;
801 if ( xD.is() )
802 aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
803 uno::Reference< io::XInputStream >() );
804 if ( aInfos.getLength() > 1 )
805 s = m_aMultiSignedStr;
806 else if ( aInfos.getLength() == 1 )
808 const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
809 s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
810 comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
812 m_xSignedValFt->set_label(s);
815 void SfxDocumentPage::ImplCheckPasswordState()
817 SfxObjectShell* pShell = SfxObjectShell::Current();
820 if (!pShell)
821 break;
822 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
823 if (!pMedSet)
824 break;
825 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pMedSet, SID_ENCRYPTIONDATA, false);
826 uno::Sequence< beans::NamedValue > aEncryptionData;
827 if (pEncryptionDataItem)
828 pEncryptionDataItem->GetValue() >>= aEncryptionData;
829 else
830 break;
832 if (!aEncryptionData.hasElements())
833 break;
834 m_xChangePassBtn->set_sensitive(true);
835 return;
837 while (false);
838 m_xChangePassBtn->set_sensitive(false);
841 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
843 return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
846 void SfxDocumentPage::EnableUseUserData()
848 bEnableUseUserData = true;
849 m_xUseUserDataCB->show();
850 m_xDeleteBtn->show();
853 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
855 bool bRet = false;
857 if ( !bHandleDelete && bEnableUseUserData &&
858 m_xUseUserDataCB->get_state_changed_from_saved() )
860 const SfxItemSet* pExpSet = GetDialogExampleSet();
861 const SfxPoolItem* pItem;
863 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
865 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
866 bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
867 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
868 rSet->Put( *pInfoItem );
869 bRet = true;
873 if ( bHandleDelete )
875 const SfxItemSet* pExpSet = GetDialogExampleSet();
876 const SfxPoolItem* pItem;
877 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
879 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
880 bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
881 SfxDocumentInfoItem newItem( *pInfoItem );
882 newItem.resetUserData( bUseAuthor
883 ? SvtUserOptions().GetFullName()
884 : OUString() );
885 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
886 newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
888 newItem.SetDeleteUserData( true );
889 rSet->Put( newItem );
890 bRet = true;
894 if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
896 const SfxItemSet* pExpSet = GetDialogExampleSet();
897 const SfxPoolItem* pItem;
899 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
901 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
902 bool bUseThumbnail = ( TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state() );
903 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave( bUseThumbnail );
904 rSet->Put( *pInfoItem );
905 bRet = true;
909 return bRet;
912 void SfxDocumentPage::Reset( const SfxItemSet* rSet )
914 // Determine the document information
915 const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
917 // template data
918 if (rInfoItem.HasTemplate())
920 const OUString& rName = rInfoItem.getTemplateName();
921 if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
922 m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
923 else
924 m_xTemplValFt->set_label(rName);
926 else
928 m_xTemplFt->hide();
929 m_xTemplValFt->hide();
932 // determine file name
933 OUString aFile( rInfoItem.GetValue() );
934 OUString aFactory( aFile );
935 if ( aFile.getLength() > 2 && aFile[0] == '[' )
937 sal_Int32 nPos = aFile.indexOf( ']' );
938 aFactory = aFile.copy( 1, nPos-1 );
939 aFile = aFile.copy( nPos+1 );
942 // determine name
943 INetURLObject aURL(aFile);
944 OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
945 if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
946 aName = SfxResId( STR_NONAME );
947 m_xNameED->set_label( aName );
949 // determine context symbol
950 aURL.SetSmartProtocol( INetProtocol::File );
951 aURL.SetSmartURL( aFactory);
952 const OUString& rMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
953 OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
954 m_xBmp->set_from_icon_name(aImage);
956 // determine size and type
957 OUString aSizeText( m_aUnknownSize );
958 if ( aURL.GetProtocol() == INetProtocol::File ||
959 aURL.isAnyKnownWebDAVScheme() )
960 aSizeText = CreateSizeText( SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
961 m_xShowSizeFT->set_label( aSizeText );
963 OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(rMainURL) );
964 if ( aDescription.isEmpty() )
965 aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
966 m_xShowTypeFT->set_label( aDescription );
968 // determine location
969 aURL.SetSmartURL( aFile);
970 if ( aURL.GetProtocol() == INetProtocol::File )
972 INetURLObject aPath( aURL );
973 aPath.setFinalSlash();
974 aPath.removeSegment();
975 // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
976 aPath.removeFinalSlash();
977 OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
978 m_xFileValEd->set_label( aText );
980 else if ( aURL.GetProtocol() != INetProtocol::PrivSoffice )
981 m_xFileValEd->set_label( aURL.GetPartBeforeLastName() );
983 // handle access data
984 bool bUseUserData = rInfoItem.IsUseUserData();
985 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
986 m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
987 rInfoItem.getCreationDate(), rLocaleWrapper ) );
988 util::DateTime aTime( rInfoItem.getModificationDate() );
989 if ( aTime.Month > 0 )
990 m_xChangeValFt->set_label( ConvertDateTime_Impl(
991 rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
992 aTime = rInfoItem.getPrintDate();
993 if ( aTime.Month > 0 )
994 m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
995 aTime, rLocaleWrapper ) );
996 const tools::Long nTime = rInfoItem.getEditingDuration();
997 if ( bUseUserData )
999 const tools::Time aT( nTime/3600, (nTime%3600)/60, nTime%60 );
1000 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aT ) );
1001 m_xDocNoValFt->set_label( OUString::number(
1002 rInfoItem.getEditingCycles() ) );
1005 bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1007 // Check for cmis properties where otherwise unavailable
1008 if ( rInfoItem.isCmisDocument( ) )
1010 const uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
1011 for ( const auto& rCmisProp : aCmisProps )
1013 if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1014 aSizeText == m_aUnknownSize )
1016 Sequence< sal_Int64 > seqValue;
1017 rCmisProp.Value >>= seqValue;
1018 SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1019 Application::GetSettings().GetLanguageTag().getLanguageType() );
1020 sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1021 if ( seqValue.hasElements() )
1023 OUString sValue;
1024 aNumberFormatter.GetInputLineString( seqValue[0], nIndex, sValue );
1025 m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1029 util::DateTime uDT;
1030 OUString emptyDate = ConvertDateTime_Impl( "", uDT, rLocaleWrapper );
1031 if ( rCmisProp.Id == "cmis:creationDate" &&
1032 (m_xCreateValFt->get_label() == emptyDate ||
1033 m_xCreateValFt->get_label().isEmpty()))
1035 Sequence< util::DateTime > seqValue;
1036 rCmisProp.Value >>= seqValue;
1037 if ( seqValue.hasElements() )
1039 m_xCreateValFt->set_label( ConvertDateTime_Impl( "", seqValue[0], rLocaleWrapper ) );
1042 if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1043 (m_xChangeValFt->get_label() == emptyDate ||
1044 m_xChangeValFt->get_label().isEmpty()))
1046 Sequence< util::DateTime > seqValue;
1047 rCmisProp.Value >>= seqValue;
1048 if ( seqValue.hasElements() )
1050 m_xChangeValFt->set_label( ConvertDateTime_Impl( "", seqValue[0], rLocaleWrapper ) );
1056 m_xUseUserDataCB->set_active(bUseUserData);
1057 m_xUseUserDataCB->save_state();
1058 m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1059 bHandleDelete = false;
1060 m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1061 m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1062 m_xUseThumbnailSaveCB->save_state();
1065 SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1066 : SfxTabDialogController(pParent, "sfx/ui/documentpropertiesdialog.ui",
1067 "DocumentPropertiesDialog", &rItemSet)
1069 const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1071 #ifdef DBG_UTIL
1072 const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1073 DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1074 #endif
1076 // Determine the Titles
1077 const SfxPoolItem* pItem = nullptr;
1078 OUString aTitle(m_xDialog->get_title());
1079 if ( SfxItemState::SET !=
1080 rItemSet.GetItemState( SID_EXPLORER_PROPS_START, false, &pItem ) )
1082 // File name
1083 const OUString& aFile( rInfoItem.GetValue() );
1085 INetURLObject aURL;
1086 aURL.SetSmartProtocol( INetProtocol::File );
1087 aURL.SetSmartURL( aFile);
1088 if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1090 OUString aLastName( aURL.GetLastName() );
1091 if ( !aLastName.isEmpty() )
1092 aTitle = aTitle.replaceFirst("%1", aLastName);
1093 else
1094 aTitle = aTitle.replaceFirst("%1", aFile);
1096 else
1097 aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1099 else
1101 DBG_ASSERT( dynamic_cast<const SfxStringItem *>(pItem) != nullptr,
1102 "SfxDocumentInfoDialog:<SfxStringItem> expected" );
1103 aTitle = aTitle.replaceFirst("%1", static_cast<const SfxStringItem*>(pItem)->GetValue());
1105 m_xDialog->set_title(aTitle);
1107 // Property Pages
1108 AddTabPage("general", SfxDocumentPage::Create, nullptr);
1109 AddTabPage("description", SfxDocumentDescPage::Create, nullptr);
1110 AddTabPage("customprops", SfxCustomPropertiesPage::Create, nullptr);
1111 if (rInfoItem.isCmisDocument())
1112 AddTabPage("cmisprops", SfxCmisPropertiesPage::Create, nullptr);
1113 else
1114 RemoveTabPage("cmisprops");
1115 AddTabPage("security", SfxSecurityPage::Create, nullptr);
1118 void SfxDocumentInfoDialog::PageCreated(const OString& rId, SfxTabPage &rPage)
1120 if (rId == "general")
1121 static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1124 void SfxDocumentInfoDialog::AddFontTabPage()
1126 AddTabPage("font", SfxResId(STR_FONT_TABPAGE), SfxDocumentFontsPage::Create);
1129 // class CustomPropertiesYesNoButton -------------------------------------
1131 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1132 std::unique_ptr<weld::RadioButton> xYesButton,
1133 std::unique_ptr<weld::RadioButton> xNoButton)
1134 : m_xTopLevel(std::move(xTopLevel))
1135 , m_xYesButton(std::move(xYesButton))
1136 , m_xNoButton(std::move(xNoButton))
1138 CheckNo();
1141 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1145 namespace {
1147 class DurationDialog_Impl : public weld::GenericDialogController
1149 std::unique_ptr<weld::CheckButton> m_xNegativeCB;
1150 std::unique_ptr<weld::SpinButton> m_xYearNF;
1151 std::unique_ptr<weld::SpinButton> m_xMonthNF;
1152 std::unique_ptr<weld::SpinButton> m_xDayNF;
1153 std::unique_ptr<weld::SpinButton> m_xHourNF;
1154 std::unique_ptr<weld::SpinButton> m_xMinuteNF;
1155 std::unique_ptr<weld::SpinButton> m_xSecondNF;
1156 std::unique_ptr<weld::SpinButton> m_xMSecondNF;
1158 public:
1159 DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration);
1160 util::Duration GetDuration() const;
1165 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1166 : GenericDialogController(pParent, "sfx/ui/editdurationdialog.ui", "EditDurationDialog")
1167 , m_xNegativeCB(m_xBuilder->weld_check_button("negative"))
1168 , m_xYearNF(m_xBuilder->weld_spin_button("years"))
1169 , m_xMonthNF(m_xBuilder->weld_spin_button("months"))
1170 , m_xDayNF(m_xBuilder->weld_spin_button("days"))
1171 , m_xHourNF(m_xBuilder->weld_spin_button("hours"))
1172 , m_xMinuteNF(m_xBuilder->weld_spin_button("minutes"))
1173 , m_xSecondNF(m_xBuilder->weld_spin_button("seconds"))
1174 , m_xMSecondNF(m_xBuilder->weld_spin_button("milliseconds"))
1176 m_xNegativeCB->set_active(rDuration.Negative);
1177 m_xYearNF->set_value(rDuration.Years);
1178 m_xMonthNF->set_value(rDuration.Months);
1179 m_xDayNF->set_value(rDuration.Days);
1180 m_xHourNF->set_value(rDuration.Hours);
1181 m_xMinuteNF->set_value(rDuration.Minutes);
1182 m_xSecondNF->set_value(rDuration.Seconds);
1183 m_xMSecondNF->set_value(rDuration.NanoSeconds);
1186 util::Duration DurationDialog_Impl::GetDuration() const
1188 util::Duration aRet;
1189 aRet.Negative = m_xNegativeCB->get_active();
1190 aRet.Years = m_xYearNF->get_value();
1191 aRet.Months = m_xMonthNF->get_value();
1192 aRet.Days = m_xDayNF->get_value();
1193 aRet.Hours = m_xHourNF->get_value();
1194 aRet.Minutes = m_xMinuteNF->get_value();
1195 aRet.Seconds = m_xSecondNF->get_value();
1196 aRet.NanoSeconds = m_xMSecondNF->get_value();
1197 return aRet;
1200 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1201 std::unique_ptr<weld::Button> xEditButton)
1202 : m_xEntry(std::move(xEntry))
1203 , m_xEditButton(std::move(xEditButton))
1205 m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1206 SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1209 void CustomPropertiesDurationField::set_visible(bool bVisible)
1211 m_xEntry->set_visible(bVisible);
1212 m_xEditButton->set_visible(bVisible);
1215 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1217 m_aDuration = rDuration;
1218 OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1219 SfxResId(SFX_ST_DURATION_FORMAT);
1220 sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1221 sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1222 sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days ) );
1223 sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours ) );
1224 sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1225 sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1226 m_xEntry->set_text(sText);
1229 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1231 DurationDialog_Impl aDurationDlg(&rButton, GetDuration());
1232 if (aDurationDlg.run() == RET_OK)
1233 SetDuration(aDurationDlg.GetDuration());
1236 namespace
1238 void fillNameBox(weld::ComboBox& rNameBox)
1240 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1241 rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1242 Size aSize(rNameBox.get_preferred_size());
1243 rNameBox.set_size_request(aSize.Width(), aSize.Height());
1246 void fillTypeBox(weld::ComboBox& rTypeBox)
1248 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1250 OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1251 rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1253 rTypeBox.set_active(0);
1254 Size aSize(rTypeBox.get_preferred_size());
1255 rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1259 // struct CustomPropertyLine ---------------------------------------------
1260 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1261 : m_pParent(pParent)
1262 , m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/linefragment.ui"))
1263 , m_xLine(m_xBuilder->weld_container("lineentry"))
1264 , m_xNameBox(m_xBuilder->weld_combo_box("namebox"))
1265 , m_xTypeBox(m_xBuilder->weld_combo_box("typebox"))
1266 , m_xValueEdit(m_xBuilder->weld_entry("valueedit"))
1267 , m_xDateTimeBox(m_xBuilder->weld_widget("datetimebox"))
1268 , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date"))))
1269 , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button("time")))
1270 , m_xDurationBox(m_xBuilder->weld_widget("durationbox"))
1271 , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry("duration"),
1272 m_xBuilder->weld_button("durationbutton")))
1273 , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget("yesno"),
1274 m_xBuilder->weld_radio_button("yes"),
1275 m_xBuilder->weld_radio_button("no")))
1276 , m_xRemoveButton(m_xBuilder->weld_button("remove"))
1277 , m_bTypeLostFocus( false )
1279 fillNameBox(*m_xNameBox);
1280 fillTypeBox(*m_xTypeBox);
1282 m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1283 m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1284 m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1285 //add lose focus handlers of date/time fields
1286 m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1289 void CustomPropertyLine::Clear()
1291 m_xNameBox->set_active(-1);
1292 m_xValueEdit->set_text(OUString());
1296 void CustomPropertyLine::Hide()
1298 m_xLine->hide();
1301 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1302 weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1303 : m_nHeight(0)
1304 , m_nLineHeight(0)
1305 , m_nScrollPos(0)
1306 , m_pCurrentLine(nullptr)
1307 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1308 Application::GetSettings().GetLanguageTag().getLanguageType())
1309 , m_rBody(rParent)
1310 , m_rHeaderAccName(rHeaderAccName)
1311 , m_rHeaderAccType(rHeaderAccType)
1312 , m_rHeaderAccValue(rHeaderAccValue)
1314 m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1315 m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1316 m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1317 m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1320 CustomPropertiesWindow::~CustomPropertiesWindow()
1322 m_aEditLoseFocusIdle.Stop();
1323 m_aBoxLoseFocusIdle.Stop();
1325 m_pCurrentLine = nullptr;
1328 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1330 auto nType = rBox.get_active_id().toInt32();
1331 m_xValueEdit->set_visible( (CUSTOM_TYPE_TEXT == nType) || (CUSTOM_TYPE_NUMBER == nType) );
1332 m_xDateTimeBox->set_visible( (CUSTOM_TYPE_DATE == nType) || (CUSTOM_TYPE_DATETIME == nType) );
1333 m_xDateField->set_visible( (CUSTOM_TYPE_DATE == nType) || (CUSTOM_TYPE_DATETIME == nType) );
1334 m_xTimeField->set_visible( CUSTOM_TYPE_DATETIME == nType );
1335 m_xDurationBox->set_visible( CUSTOM_TYPE_DURATION == nType );
1336 m_xDurationField->set_visible( CUSTOM_TYPE_DURATION == nType );
1337 m_xYesNoButton->set_visible( CUSTOM_TYPE_BOOLEAN == nType );
1340 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1342 DoTypeHdl(rBox);
1345 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1347 StoreCustomProperties();
1349 auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1350 [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1351 if ( pFound != m_aCustomPropertiesLines.end() )
1353 sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1354 sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1355 m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1357 ReloadLinesContent();
1360 m_aRemovedHdl.Call(nullptr);
1363 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1365 m_pParent->Remove(this);
1368 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1370 m_pCurrentLine = pLine;
1371 m_aEditLoseFocusIdle.Start();
1374 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1376 if (!m_bTypeLostFocus)
1377 m_pParent->EditLoseFocus(this);
1378 else
1379 m_bTypeLostFocus = false;
1382 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1384 m_pCurrentLine = pLine;
1385 m_aBoxLoseFocusIdle.Start();
1388 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1390 m_pParent->BoxLoseFocus(this);
1393 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1395 ValidateLine( m_pCurrentLine, false );
1398 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1400 ValidateLine( m_pCurrentLine, true );
1403 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1405 bool bIsValid = true;
1406 pLine->m_bTypeLostFocus = false;
1407 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1408 OUString sValue = pLine->m_xValueEdit->get_text();
1409 if ( sValue.isEmpty() )
1410 return true;
1412 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1413 if ( CUSTOM_TYPE_NUMBER == nType )
1414 // tdf#116214 Scientific format allows to use also standard numbers
1415 nIndex = const_cast< SvNumberFormatter& >(
1416 m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1417 else if ( CUSTOM_TYPE_DATE == nType )
1418 nIndex = const_cast< SvNumberFormatter& >(
1419 m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1421 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1423 sal_uInt32 nTemp = nIndex;
1424 double fDummy = 0.0;
1425 bIsValid = const_cast< SvNumberFormatter& >(
1426 m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1427 if ( bIsValid && nTemp != nIndex )
1428 // sValue is a number but the format doesn't match the index
1429 bIsValid = false;
1432 return bIsValid;
1435 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1437 if (pLine && !IsLineValid(pLine))
1439 if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1440 pLine->m_bTypeLostFocus = true;
1441 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1442 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1443 if (xMessageBox->run() == RET_OK)
1444 pLine->m_xTypeBox->set_active_id(OUString::number(CUSTOM_TYPE_TEXT));
1445 else
1446 pLine->m_xValueEdit->grab_focus();
1450 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1452 while (GetExistingLineCount() < nCount)
1454 CreateNewLine();
1458 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1460 m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1461 ReloadLinesContent();
1464 void CustomPropertiesWindow::CreateNewLine()
1466 CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1467 pNewLine->m_xNameBox->set_accessible_relation_labeled_by(&m_rHeaderAccName);
1468 pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1469 pNewLine->m_xTypeBox->set_accessible_relation_labeled_by(&m_rHeaderAccType);
1470 pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1471 pNewLine->m_xValueEdit->set_accessible_relation_labeled_by(&m_rHeaderAccValue);
1472 pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1474 m_aCustomPropertiesLines.emplace_back( pNewLine );
1476 pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1477 pNewLine->m_xNameBox->grab_focus();
1480 bool CustomPropertiesWindow::AreAllLinesValid() const
1482 bool bRet = true;
1483 for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1485 if ( !IsLineValid( pLine.get() ) )
1487 bRet = false;
1488 break;
1492 return bRet;
1495 void CustomPropertiesWindow::ClearAllLines()
1497 for (auto& pLine : m_aCustomPropertiesLines)
1499 pLine->Clear();
1501 m_pCurrentLine = nullptr;
1502 m_aCustomProperties.clear();
1503 m_nScrollPos = 0;
1506 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1508 StoreCustomProperties();
1509 m_nScrollPos += nNewPos;
1510 ReloadLinesContent();
1513 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1515 StoreCustomProperties();
1517 Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1519 for (sal_uInt32 i = 0; i < GetTotalLineCount(); ++i)
1521 aPropertiesSeq[i].Name = m_aCustomProperties[i]->m_sName;
1522 aPropertiesSeq[i].Value = m_aCustomProperties[i]->m_aValue;
1525 return aPropertiesSeq;
1528 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1529 : m_xTimeField(std::move(xTimeField))
1530 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1531 , m_isUTC(false)
1533 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1534 m_xFormatter->EnableEmptyField(false);
1537 tools::Time CustomPropertiesTimeField::get_value() const
1539 return m_xFormatter->GetTime();
1542 void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1544 m_xFormatter->SetTime(rTime);
1547 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1551 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1552 : m_xDateField(pDateField)
1554 DateTime aDateTime(DateTime::SYSTEM);
1555 m_xDateField->set_date(aDateTime);
1558 void CustomPropertiesDateField::set_visible(bool bVisible)
1560 m_xDateField->set_visible(bVisible);
1563 Date CustomPropertiesDateField::get_date() const
1565 return m_xDateField->get_date();
1568 void CustomPropertiesDateField::set_date(const Date& rDate)
1570 m_xDateField->set_date(rDate);
1573 CustomPropertiesDateField::~CustomPropertiesDateField()
1577 void CustomPropertiesWindow::StoreCustomProperties()
1579 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1581 for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1583 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1585 OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1586 if (!sPropertyName.isEmpty())
1588 m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1589 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1590 if (CUSTOM_TYPE_NUMBER == nType)
1592 double nValue = 0;
1593 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1594 bool bIsNum = m_aNumberFormatter.
1595 IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1596 if (bIsNum)
1597 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1599 else if (CUSTOM_TYPE_BOOLEAN == nType)
1601 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1602 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1604 else if (CUSTOM_TYPE_DATETIME == nType)
1606 Date aTmpDate = pLine->m_xDateField->get_date();
1607 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1608 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1609 aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1610 aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1611 pLine->m_xTimeField->m_isUTC);
1612 if (pLine->m_xDateField->m_TZ)
1614 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1615 aDateTime, *pLine->m_xDateField->m_TZ);
1617 else
1619 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1622 else if (CUSTOM_TYPE_DATE == nType)
1624 Date aTmpDate = pLine->m_xDateField->get_date();
1625 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1626 aTmpDate.GetYear());
1627 if (pLine->m_xDateField->m_TZ)
1629 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1630 aDate, *pLine->m_xDateField->m_TZ);
1632 else
1634 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1637 else if (CUSTOM_TYPE_DURATION == nType)
1639 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1641 else
1643 OUString sValue(pLine->m_xValueEdit->get_text());
1644 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1650 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1652 m_aCustomProperties = std::move(rProperties);
1653 ReloadLinesContent();
1656 void CustomPropertiesWindow::ReloadLinesContent()
1658 double nTmpValue = 0;
1659 bool bTmpValue = false;
1660 OUString sTmpValue;
1661 util::DateTime aTmpDateTime;
1662 util::Date aTmpDate;
1663 util::DateTimeWithTimezone aTmpDateTimeTZ;
1664 util::DateWithTimezone aTmpDateTZ;
1665 util::Duration aTmpDuration;
1666 SvtSysLocale aSysLocale;
1667 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1668 sal_IntPtr nType = CUSTOM_TYPE_UNKNOWN;
1669 OUString sValue;
1671 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1672 sal_uInt32 i = 0;
1674 for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1676 const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1677 const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1679 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1680 pLine->Clear();
1682 pLine->m_xNameBox->set_entry_text(rName);
1683 pLine->m_xLine->show();
1685 if (!rAny.hasValue())
1687 pLine->m_xValueEdit->set_text(OUString());
1689 else if (rAny >>= nTmpValue)
1691 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1692 m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex, sValue);
1693 pLine->m_xValueEdit->set_text(sValue);
1694 nType = CUSTOM_TYPE_NUMBER;
1696 else if (rAny >>= bTmpValue)
1698 sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1699 nType = CUSTOM_TYPE_BOOLEAN;
1701 else if (rAny >>= sTmpValue)
1703 pLine->m_xValueEdit->set_text(sTmpValue);
1704 nType = CUSTOM_TYPE_TEXT;
1706 else if (rAny >>= aTmpDate)
1708 pLine->m_xDateField->set_date(Date(aTmpDate));
1709 nType = CUSTOM_TYPE_DATE;
1711 else if (rAny >>= aTmpDateTime)
1713 pLine->m_xDateField->set_date(Date(aTmpDateTime));
1714 pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1715 pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1716 nType = CUSTOM_TYPE_DATETIME;
1718 else if (rAny >>= aTmpDateTZ)
1720 pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1721 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1722 pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1723 nType = CUSTOM_TYPE_DATE;
1725 else if (rAny >>= aTmpDateTimeTZ)
1727 util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1728 pLine->m_xDateField->set_date(Date(rDT));
1729 pLine->m_xTimeField->set_value(tools::Time(rDT));
1730 pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1731 pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1732 nType = CUSTOM_TYPE_DATETIME;
1734 else if (rAny >>= aTmpDuration)
1736 nType = CUSTOM_TYPE_DURATION;
1737 pLine->m_xDurationField->SetDuration(aTmpDuration);
1740 if (nType != CUSTOM_TYPE_UNKNOWN)
1742 if (CUSTOM_TYPE_BOOLEAN == nType)
1744 if (bTmpValue)
1745 pLine->m_xYesNoButton->CheckYes();
1746 else
1747 pLine->m_xYesNoButton->CheckNo();
1749 pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1752 pLine->DoTypeHdl(*pLine->m_xTypeBox);
1755 while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1757 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1758 pLine->Hide();
1759 i++;
1763 CustomPropertiesControl::CustomPropertiesControl()
1764 : m_nThumbPos(0)
1768 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
1770 m_xBox = rBuilder.weld_widget("box");
1771 m_xBody = rBuilder.weld_container("properties");
1773 m_xName = rBuilder.weld_label("name");
1774 m_xType = rBuilder.weld_label("type");
1775 m_xValue = rBuilder.weld_label("value");
1776 m_xVertScroll = rBuilder.weld_scrolled_window("scroll", true);
1777 m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
1779 m_xBox->set_stack_background();
1780 m_xVertScroll->show();
1782 std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
1783 Size aLineSize(xNewLine->m_xLine->get_preferred_size());
1784 m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
1785 m_xBody->set_size_request(aLineSize.Width() + 6, -1);
1786 auto nHeight = aLineSize.Height() * 8;
1787 m_xVertScroll->set_size_request(-1, nHeight + 6);
1789 m_xPropertiesWin->SetHeight(nHeight);
1790 m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
1792 m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
1793 m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
1794 m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
1796 m_xBody->move(xNewLine->m_xLine.get(), nullptr);
1797 xNewLine.reset();
1799 m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
1801 m_xVertScroll->vadjustment_set_lower(0);
1802 m_xVertScroll->vadjustment_set_upper(0);
1803 m_xVertScroll->vadjustment_set_page_size(0xFFFF);
1805 Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
1806 m_xVertScroll->connect_vadjustment_changed(aScrollLink);
1808 ResizeHdl(Size(-1, nHeight));
1811 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
1813 int nHeight = rSize.Height() - 6;
1814 if (nHeight == m_xPropertiesWin->GetHeight())
1815 return;
1816 m_xPropertiesWin->SetHeight(nHeight);
1817 sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
1818 sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
1819 m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
1820 m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
1821 m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
1822 m_xPropertiesWin->ReloadLinesContent();
1825 CustomPropertiesControl::~CustomPropertiesControl()
1829 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
1831 sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
1832 int nThumbPos = rScrollBar.vadjustment_get_value();
1833 nOffset *= ( m_nThumbPos - nThumbPos );
1834 m_nThumbPos = nThumbPos;
1835 m_xPropertiesWin->DoScroll( nOffset );
1838 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
1840 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1841 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1842 if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
1844 m_xVertScroll->vadjustment_set_value(nLineCount - 1);
1845 ScrollHdl(*m_xVertScroll);
1849 void CustomPropertiesControl::AddLine( Any const & rAny )
1851 m_xPropertiesWin->AddLine( OUString(), rAny );
1852 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1853 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1854 if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
1856 m_xVertScroll->vadjustment_set_value(nLineCount + 1);
1857 ScrollHdl(*m_xVertScroll);
1861 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1863 m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
1864 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1865 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1868 // class SfxCustomPropertiesPage -----------------------------------------
1869 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
1870 : SfxTabPage(pPage, pController, "sfx/ui/custominfopage.ui", "CustomInfoPage", &rItemSet)
1871 , m_xPropertiesCtrl(new CustomPropertiesControl)
1872 , m_xAdd(m_xBuilder->weld_button("add"))
1874 m_xPropertiesCtrl->Init(*m_xBuilder);
1875 m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
1878 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
1880 m_xPropertiesCtrl.reset();
1883 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
1885 // tdf#115853: reload current lines before adding a brand new one
1886 // indeed the info are deleted by ClearCustomProperties
1887 // each time SfxDocumentInfoItem destructor is called
1888 SfxDocumentInfoItem pInfo;
1889 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1890 for ( const auto& rProperty : aPropertySeq )
1892 if ( !rProperty.Name.isEmpty() )
1894 pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
1898 Any aAny;
1899 m_xPropertiesCtrl->AddLine(aAny);
1902 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
1904 const SfxPoolItem* pItem = nullptr;
1905 SfxDocumentInfoItem* pInfo = nullptr;
1906 bool bMustDelete = false;
1908 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
1910 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
1911 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
1912 else
1914 bMustDelete = true;
1915 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
1919 if ( pInfo )
1921 // If it's a CMIS document, we can't save custom properties
1922 if ( pInfo->isCmisDocument( ) )
1924 if ( bMustDelete )
1925 delete pInfo;
1926 return false;
1929 pInfo->ClearCustomProperties();
1930 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1931 for ( const auto& rProperty : aPropertySeq )
1933 if ( !rProperty.Name.isEmpty() )
1934 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
1938 if (pInfo)
1940 rSet->Put(*pInfo);
1941 if ( bMustDelete )
1942 delete pInfo;
1944 return true;
1947 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
1949 m_xPropertiesCtrl->ClearAllLines();
1950 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
1951 std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
1952 m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
1955 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
1957 DeactivateRC nRet = DeactivateRC::LeavePage;
1958 if ( !m_xPropertiesCtrl->AreAllLinesValid() )
1959 nRet = DeactivateRC::KeepPage;
1960 return nRet;
1963 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
1965 return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
1968 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
1969 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1970 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1971 , m_xValueEdit(m_xBuilder->weld_entry("value"))
1973 m_xValueEdit->show();
1974 m_xValueEdit->set_text(aStr);
1977 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
1978 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1979 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1980 , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date")))
1981 , m_xTimeField(m_xBuilder->weld_formatted_spin_button("time"))
1982 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1984 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1985 m_xFormatter->EnableEmptyField(false);
1987 m_xDateField->show();
1988 m_xTimeField->show();
1989 m_xDateField->set_date(Date(aDateTime));
1990 m_xFormatter->SetTime(tools::Time(aDateTime));
1993 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
1994 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1995 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1996 , m_xYesButton(m_xBuilder->weld_radio_button("yes"))
1997 , m_xNoButton(m_xBuilder->weld_radio_button("no"))
1999 m_xYesButton->show();
2000 m_xNoButton->show();
2001 if (bValue)
2002 m_xYesButton->set_active(true);
2003 else
2004 m_xNoButton->set_active(true);
2007 // struct CmisPropertyLine ---------------------------------------------
2008 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2009 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2010 , m_sType(CMIS_TYPE_STRING)
2011 , m_bUpdatable(false)
2012 , m_bRequired(false)
2013 , m_bMultiValued(false)
2014 , m_bOpenChoice(false)
2015 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2016 , m_xName(m_xBuilder->weld_label("name"))
2017 , m_xType(m_xBuilder->weld_label("type"))
2019 m_xFrame->set_sensitive(true);
2022 CmisPropertyLine::~CmisPropertyLine( )
2026 // class CmisPropertiesWindow -----------------------------------------
2028 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2029 : m_xBox(std::move(xParent))
2030 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2031 Application::GetSettings().GetLanguageTag().getLanguageType())
2035 CmisPropertiesWindow::~CmisPropertiesWindow()
2039 void CmisPropertiesWindow::ClearAllLines()
2041 m_aCmisPropertiesLines.clear();
2044 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2045 const OUString& sType, const bool bUpdatable,
2046 const bool bRequired, const bool bMultiValued,
2047 const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2049 std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2051 pNewLine->m_sId = sId;
2052 pNewLine->m_sType = sType;
2053 pNewLine->m_bUpdatable = bUpdatable;
2054 pNewLine->m_bRequired = bRequired;
2055 pNewLine->m_bMultiValued = bMultiValued;
2056 pNewLine->m_bOpenChoice = bOpenChoice;
2058 if ( sType == CMIS_TYPE_INTEGER )
2060 Sequence< sal_Int64 > seqValue;
2061 rAny >>= seqValue;
2062 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2063 for ( const auto& rValue : std::as_const(seqValue) )
2065 OUString sValue;
2066 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2067 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2068 pValue->m_xValueEdit->set_editable(bUpdatable);
2069 pNewLine->m_aValues.push_back( std::move(pValue) );
2072 else if ( sType == CMIS_TYPE_DECIMAL )
2074 Sequence< double > seqValue;
2075 rAny >>= seqValue;
2076 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2077 for ( const auto& rValue : std::as_const(seqValue) )
2079 OUString sValue;
2080 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2081 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2082 pValue->m_xValueEdit->set_editable(bUpdatable);
2083 pNewLine->m_aValues.push_back( std::move(pValue) );
2087 else if ( sType == CMIS_TYPE_BOOL )
2089 Sequence<sal_Bool> seqValue;
2090 rAny >>= seqValue;
2091 for ( const auto& rValue : std::as_const(seqValue) )
2093 std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2094 pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2095 pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2096 pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2099 else if ( sType == CMIS_TYPE_STRING )
2101 Sequence< OUString > seqValue;
2102 rAny >>= seqValue;
2103 for ( const auto& rValue : std::as_const(seqValue) )
2105 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2106 pValue->m_xValueEdit->set_editable(bUpdatable);
2107 pNewLine->m_aValues.push_back( std::move(pValue) );
2110 else if ( sType == CMIS_TYPE_DATETIME )
2112 Sequence< util::DateTime > seqValue;
2113 rAny >>= seqValue;
2114 for ( const auto& rValue : std::as_const(seqValue) )
2116 std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2117 pDateTime->m_xDateField->set_sensitive(bUpdatable);
2118 pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2119 pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2122 pNewLine->m_xName->set_label( sName );
2123 pNewLine->m_xName->show();
2124 pNewLine->m_xType->set_label( sType );
2125 pNewLine->m_xType->show();
2127 m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2130 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2132 Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2133 sal_Int32 i = 0;
2134 for ( auto& rxLine : m_aCmisPropertiesLines )
2136 CmisPropertyLine* pLine = rxLine.get();
2138 aPropertiesSeq[i].Id = pLine->m_sId;
2139 aPropertiesSeq[i].Type = pLine->m_sType;
2140 aPropertiesSeq[i].Updatable = pLine->m_bUpdatable;
2141 aPropertiesSeq[i].Required = pLine->m_bRequired;
2142 aPropertiesSeq[i].OpenChoice = pLine->m_bOpenChoice;
2143 aPropertiesSeq[i].MultiValued = pLine->m_bMultiValued;
2145 OUString sPropertyName = pLine->m_xName->get_label();
2146 if ( !sPropertyName.isEmpty() )
2148 aPropertiesSeq[i].Name = sPropertyName;
2149 OUString sType = pLine->m_xType->get_label();
2150 if ( CMIS_TYPE_DECIMAL == sType )
2152 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2153 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2154 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2155 sal_Int32 k = 0;
2156 for ( const auto& rxValue : pLine->m_aValues )
2158 double dValue = 0.0;
2159 OUString sValue( rxValue->m_xValueEdit->get_text() );
2160 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2161 IsNumberFormat( sValue, nIndex, dValue );
2162 if ( bIsNum )
2163 seqValue[k] = dValue;
2164 ++k;
2166 aPropertiesSeq[i].Value <<= seqValue;
2168 else if ( CMIS_TYPE_INTEGER == sType )
2170 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2171 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2172 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2173 sal_Int32 k = 0;
2174 for ( const auto& rxValue : pLine->m_aValues )
2176 double dValue = 0;
2177 OUString sValue( rxValue->m_xValueEdit->get_text() );
2178 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2179 IsNumberFormat( sValue, nIndex, dValue );
2180 if ( bIsNum )
2181 seqValue[k] = static_cast<sal_Int64>(dValue);
2182 ++k;
2184 aPropertiesSeq[i].Value <<= seqValue;
2186 else if ( CMIS_TYPE_BOOL == sType )
2188 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2189 sal_Int32 k = 0;
2190 for ( const auto& rxYesNo : pLine->m_aYesNos )
2192 bool bValue = rxYesNo->m_xYesButton->get_active();
2193 seqValue[k] = bValue;
2194 ++k;
2196 aPropertiesSeq[i].Value <<= seqValue;
2199 else if ( CMIS_TYPE_DATETIME == sType )
2201 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2202 sal_Int32 k = 0;
2203 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2205 Date aTmpDate = rxDateTime->m_xDateField->get_date();
2206 tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2207 util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2208 aTmpTime.GetMin(), aTmpTime.GetHour(),
2209 aTmpDate.GetDay(), aTmpDate.GetMonth(),
2210 aTmpDate.GetYear(), true );
2211 seqValue[k] = aDateTime;
2212 ++k;
2214 aPropertiesSeq[i].Value <<= seqValue;
2216 else
2218 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2219 sal_Int32 k = 0;
2220 for ( const auto& rxValue : pLine->m_aValues )
2222 OUString sValue( rxValue->m_xValueEdit->get_text() );
2223 seqValue[k] = sValue;
2224 ++k;
2226 aPropertiesSeq[i].Value <<= seqValue;
2229 ++i;
2232 return aPropertiesSeq;
2235 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2236 : m_aPropertiesWin(rBuilder.weld_container("CmisWindow"))
2237 , m_xScrolledWindow(rBuilder.weld_scrolled_window("CmisScroll"))
2239 // set height to something small and force it to take the size
2240 // dictated by the other pages
2241 m_xScrolledWindow->set_size_request(-1, 42);
2244 void CmisPropertiesControl::ClearAllLines()
2246 m_aPropertiesWin.ClearAllLines();
2249 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2250 const OUString& sType, const bool bUpdatable,
2251 const bool bRequired, const bool bMultiValued,
2252 const bool bOpenChoice, Any& aChoices, Any const & rAny
2255 m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2256 bOpenChoice, aChoices, rAny );
2259 // class SfxCmisPropertiesPage -----------------------------------------
2260 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2261 : SfxTabPage(pPage, pController, "sfx/ui/cmisinfopage.ui", "CmisInfoPage", &rItemSet)
2262 , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2266 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2268 m_xPropertiesCtrl.reset();
2271 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2273 const SfxPoolItem* pItem = nullptr;
2274 SfxDocumentInfoItem* pInfo = nullptr;
2275 bool bMustDelete = false;
2277 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2279 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
2280 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2281 else
2283 bMustDelete = true;
2284 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
2288 sal_Int32 modifiedNum = 0;
2289 if ( pInfo )
2291 Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2292 Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2294 std::vector< document::CmisProperty > changedProps;
2295 for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2297 if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2299 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2301 Sequence< util::DateTime > oldValue;
2302 aOldProps[i].Value >>= oldValue;
2303 // We only edit hours and minutes
2304 // don't compare NanoSeconds and Seconds
2305 for ( auto& rDateTime : oldValue )
2307 rDateTime.NanoSeconds = 0;
2308 rDateTime.Seconds = 0;
2310 Sequence< util::DateTime > newValue;
2311 aNewProps[i].Value >>= newValue;
2312 if ( oldValue != newValue )
2314 modifiedNum++;
2315 changedProps.push_back( aNewProps[i] );
2318 else if ( aOldProps[i].Value != aNewProps[i].Value )
2320 modifiedNum++;
2321 changedProps.push_back( aNewProps[i] );
2325 Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2326 pInfo->SetCmisProperties( aModifiedProps );
2327 rSet->Put( *pInfo );
2328 if ( bMustDelete )
2329 delete pInfo;
2332 return modifiedNum;
2335 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2337 m_xPropertiesCtrl->ClearAllLines();
2338 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2339 uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2340 for ( auto& rCmisProp : aCmisProps )
2342 m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2343 rCmisProp.Name,
2344 rCmisProp.Type,
2345 rCmisProp.Updatable,
2346 rCmisProp.Required,
2347 rCmisProp.MultiValued,
2348 rCmisProp.OpenChoice,
2349 rCmisProp.Choices,
2350 rCmisProp.Value);
2354 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2356 return DeactivateRC::LeavePage;
2359 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2361 return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2364 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */