Version 7.6.3.2-android, tag libreoffice-7.6.3.2-android
[LibreOffice.git] / sfx2 / source / dialog / dinfdlg.cxx
blob7d97ab8b3ba8e69578b8fd110adba017006c03ec
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 <utility>
25 #include <vcl/svapp.hxx>
26 #include <vcl/weld.hxx>
27 #include <vcl/weldutils.hxx>
28 #include <unotools/datetime.hxx>
29 #include <unotools/localedatawrapper.hxx>
30 #include <unotools/cmdoptions.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/propertyvalue.hxx>
33 #include <comphelper/stl_types.hxx>
34 #include <comphelper/xmlsechelper.hxx>
35 #include <unotools/useroptions.hxx>
36 #include <svtools/ctrlbox.hxx>
37 #include <svtools/imagemgr.hxx>
38 #include <sal/log.hxx>
39 #include <osl/diagnose.h>
40 #include <osl/file.hxx>
41 #include <comphelper/lok.hxx>
43 #include <memory>
45 #include <comphelper/sequence.hxx>
46 #include <comphelper/string.hxx>
47 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
48 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
49 #include <unotools/syslocale.hxx>
50 #include <rtl/math.hxx>
51 #include <com/sun/star/beans/PropertyAttribute.hpp>
52 #include <com/sun/star/beans/XPropertyContainer.hpp>
53 #include <com/sun/star/beans/XPropertySet.hpp>
54 #include <com/sun/star/util/DateTime.hpp>
55 #include <com/sun/star/util/Date.hpp>
56 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
57 #include <com/sun/star/util/DateWithTimezone.hpp>
58 #include <com/sun/star/util/Duration.hpp>
59 #include <com/sun/star/document/XDocumentProperties.hpp>
60 #include <com/sun/star/document/CmisProperty.hpp>
61 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
63 #include <vcl/timer.hxx>
64 #include <vcl/settings.hxx>
65 #include <sfx2/sfxresid.hxx>
66 #include <sfx2/frame.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 #include <vcl/abstdlg.hxx>
75 #include <documentfontsdialog.hxx>
76 #include <dinfdlg.hrc>
77 #include <sfx2/strings.hrc>
78 #include <strings.hxx>
79 #include <comphelper/diagnose_ex.hxx>
80 #include "securitypage.hxx"
82 #include <algorithm>
84 using namespace ::com::sun::star;
85 using namespace ::com::sun::star::uno;
87 struct CustomProperty
89 OUString m_sName;
90 css::uno::Any m_aValue;
92 CustomProperty( OUString sName, css::uno::Any aValue ) :
93 m_sName(std::move( sName )), m_aValue(std::move( aValue )) {}
95 bool operator==(const CustomProperty& rProp) const
97 return m_sName == rProp.m_sName && m_aValue == rProp.m_aValue;
101 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
103 namespace {
105 OUString CreateSizeText( sal_Int64 nSize )
107 OUString aUnitStr = " " + SfxResId(STR_BYTES);
108 sal_Int64 nSize1 = nSize;
109 sal_Int64 nSize2 = nSize1;
110 sal_Int64 nMega = 1024 * 1024;
111 sal_Int64 nGiga = nMega * 1024;
112 double fSize = nSize;
113 int nDec = 0;
115 if ( nSize1 >= 10000 && nSize1 < nMega )
117 nSize1 /= 1024;
118 aUnitStr = " " + SfxResId(STR_KB);
119 fSize /= 1024;
120 nDec = 0;
122 else if ( nSize1 >= nMega && nSize1 < nGiga )
124 nSize1 /= nMega;
125 aUnitStr = " " + SfxResId(STR_MB);
126 fSize /= nMega;
127 nDec = 2;
129 else if ( nSize1 >= nGiga )
131 nSize1 /= nGiga;
132 aUnitStr = " " + SfxResId(STR_GB);
133 fSize /= nGiga;
134 nDec = 3;
136 const SvtSysLocale aSysLocale;
137 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
138 OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
139 if ( nSize1 < nSize2 )
141 aSizeStr = ::rtl::math::doubleToUString( fSize,
142 rtl_math_StringFormat_F, nDec,
143 rLocaleWrapper.getNumDecimalSep()[0] )
144 + aUnitStr
145 + " ("
146 + rLocaleWrapper.getNum( nSize2, 0 )
147 + " "
148 + SfxResId(STR_BYTES)
149 + ")";
151 return aSizeStr;
154 OUString ConvertDateTime_Impl( std::u16string_view rName,
155 const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
157 Date aD(uDT);
158 tools::Time aT(uDT);
159 static const OUStringLiteral aDelim( u", " );
160 OUString aStr = rWrapper.getDate( aD )
161 + aDelim
162 + rWrapper.getTime( aT );
163 std::u16string_view aAuthor = comphelper::string::stripStart(rName, ' ');
164 if (!aAuthor.empty())
166 aStr += aDelim + aAuthor;
168 return aStr;
174 SfxDocumentInfoItem::SfxDocumentInfoItem()
175 : m_AutoloadDelay(0)
176 , m_isAutoloadEnabled(false)
177 , m_EditingCycles(0)
178 , m_EditingDuration(0)
179 , m_bHasTemplate( true )
180 , m_bDeleteUserData( false )
181 , m_bUseUserData( true )
182 , m_bUseThumbnailSave( true )
186 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
187 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
188 const uno::Sequence<document::CmisProperty>& i_cmisProps,
189 bool bIs, bool _bIs )
190 : SfxStringItem( SID_DOCINFO, rFile )
191 , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
192 , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
193 , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
194 , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
195 , m_TemplateName( i_xDocProps->getTemplateName() )
196 , m_Author( i_xDocProps->getAuthor() )
197 , m_CreationDate( i_xDocProps->getCreationDate() )
198 , m_ModifiedBy( i_xDocProps->getModifiedBy() )
199 , m_ModificationDate( i_xDocProps->getModificationDate() )
200 , m_PrintedBy( i_xDocProps->getPrintedBy() )
201 , m_PrintDate( i_xDocProps->getPrintDate() )
202 , m_EditingCycles( i_xDocProps->getEditingCycles() )
203 , m_EditingDuration( i_xDocProps->getEditingDuration() )
204 , m_Description( i_xDocProps->getDescription() )
205 , m_Keywords( ::comphelper::string::convertCommaSeparated(
206 i_xDocProps->getKeywords()) )
207 , m_Subject( i_xDocProps->getSubject() )
208 , m_Title( i_xDocProps->getTitle() )
209 , m_bHasTemplate( true )
210 , m_bDeleteUserData( false )
211 , m_bUseUserData( bIs )
212 , m_bUseThumbnailSave( _bIs )
216 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
217 if ( xContainer.is() )
219 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
220 const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
221 for ( const beans::Property& rProp : lProps )
223 // "fix" property? => not a custom property => ignore it!
224 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
226 SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
227 continue;
230 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
231 AddCustomProperty( rProp.Name, aValue );
235 // get CMIS properties
236 m_aCmisProperties = i_cmisProps;
238 catch ( Exception& ) {}
242 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
243 : SfxStringItem( rItem )
244 , m_AutoloadDelay( rItem.getAutoloadDelay() )
245 , m_AutoloadURL( rItem.getAutoloadURL() )
246 , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
247 , m_DefaultTarget( rItem.getDefaultTarget() )
248 , m_TemplateName( rItem.getTemplateName() )
249 , m_Author( rItem.getAuthor() )
250 , m_CreationDate( rItem.getCreationDate() )
251 , m_ModifiedBy( rItem.getModifiedBy() )
252 , m_ModificationDate( rItem.getModificationDate() )
253 , m_PrintedBy( rItem.getPrintedBy() )
254 , m_PrintDate( rItem.getPrintDate() )
255 , m_EditingCycles( rItem.getEditingCycles() )
256 , m_EditingDuration( rItem.getEditingDuration() )
257 , m_Description( rItem.getDescription() )
258 , m_Keywords( rItem.getKeywords() )
259 , m_Subject( rItem.getSubject() )
260 , m_Title( rItem.getTitle() )
261 , m_bHasTemplate( rItem.m_bHasTemplate )
262 , m_bDeleteUserData( rItem.m_bDeleteUserData )
263 , m_bUseUserData( rItem.m_bUseUserData )
264 , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
266 for (auto const & pOtherProp : rItem.m_aCustomProperties)
268 AddCustomProperty( pOtherProp->m_sName, pOtherProp->m_aValue );
271 m_aCmisProperties = rItem.m_aCmisProperties;
274 SfxDocumentInfoItem::~SfxDocumentInfoItem()
276 ClearCustomProperties();
279 SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
281 return new SfxDocumentInfoItem( *this );
284 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
286 if (!SfxStringItem::operator==(rItem))
287 return false;
288 const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
290 return
291 m_AutoloadDelay == rInfoItem.m_AutoloadDelay &&
292 m_AutoloadURL == rInfoItem.m_AutoloadURL &&
293 m_isAutoloadEnabled == rInfoItem.m_isAutoloadEnabled &&
294 m_DefaultTarget == rInfoItem.m_DefaultTarget &&
295 m_Author == rInfoItem.m_Author &&
296 m_CreationDate == rInfoItem.m_CreationDate &&
297 m_ModifiedBy == rInfoItem.m_ModifiedBy &&
298 m_ModificationDate == rInfoItem.m_ModificationDate &&
299 m_PrintedBy == rInfoItem.m_PrintedBy &&
300 m_PrintDate == rInfoItem.m_PrintDate &&
301 m_EditingCycles == rInfoItem.m_EditingCycles &&
302 m_EditingDuration == rInfoItem.m_EditingDuration &&
303 m_Description == rInfoItem.m_Description &&
304 m_Keywords == rInfoItem.m_Keywords &&
305 m_Subject == rInfoItem.m_Subject &&
306 m_Title == rInfoItem.m_Title &&
307 comphelper::ContainerUniquePtrEquals(m_aCustomProperties, rInfoItem.m_aCustomProperties) &&
308 m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
312 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
314 m_Author = i_rAuthor;
315 DateTime now( DateTime::SYSTEM );
316 m_CreationDate = now.GetUNODateTime();
317 m_ModifiedBy = OUString();
318 m_PrintedBy = OUString();
319 m_ModificationDate = util::DateTime();
320 m_PrintDate = util::DateTime();
321 m_EditingDuration = 0;
322 m_EditingCycles = 1;
326 void SfxDocumentInfoItem::UpdateDocumentInfo(
327 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
328 bool i_bDoNotUpdateUserDefined) const
330 if (isAutoloadEnabled()) {
331 i_xDocProps->setAutoloadSecs(getAutoloadDelay());
332 i_xDocProps->setAutoloadURL(getAutoloadURL());
333 } else {
334 i_xDocProps->setAutoloadSecs(0);
335 i_xDocProps->setAutoloadURL(OUString());
337 i_xDocProps->setDefaultTarget(getDefaultTarget());
338 i_xDocProps->setAuthor(getAuthor());
339 i_xDocProps->setCreationDate(getCreationDate());
340 i_xDocProps->setModifiedBy(getModifiedBy());
341 i_xDocProps->setModificationDate(getModificationDate());
342 i_xDocProps->setPrintedBy(getPrintedBy());
343 i_xDocProps->setPrintDate(getPrintDate());
344 i_xDocProps->setEditingCycles(getEditingCycles());
345 i_xDocProps->setEditingDuration(getEditingDuration());
346 i_xDocProps->setDescription(getDescription());
347 i_xDocProps->setKeywords(
348 ::comphelper::string::convertCommaSeparated(getKeywords()));
349 i_xDocProps->setSubject(getSubject());
350 i_xDocProps->setTitle(getTitle());
352 // this is necessary in case of replaying a recorded macro:
353 // in this case, the macro may contain the 4 old user-defined DocumentInfo
354 // fields, but not any of the DocumentInfo properties;
355 // as a consequence, most of the UserDefined properties of the
356 // DocumentProperties would be summarily deleted here, which does not
357 // seem like a good idea.
358 if (i_bDoNotUpdateUserDefined)
359 return;
363 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
364 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
365 Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
366 const Sequence< beans::Property > lProps = xSetInfo->getProperties();
367 for ( const beans::Property& rProp : lProps )
369 if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
371 xContainer->removeProperty( rProp.Name );
375 for (auto const & pProp : m_aCustomProperties)
379 xContainer->addProperty( pProp->m_sName,
380 beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
382 catch ( Exception const & )
384 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
388 catch ( Exception const & )
390 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
395 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
397 m_bDeleteUserData = bSet;
401 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
403 m_bUseUserData = bSet;
406 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
408 m_bUseThumbnailSave = bSet;
411 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
413 std::vector< std::unique_ptr<CustomProperty> > aRet;
414 for (auto const & pOtherProp : m_aCustomProperties)
416 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
417 pOtherProp->m_aValue ));
418 aRet.push_back( std::move(pProp) );
421 return aRet;
424 void SfxDocumentInfoItem::ClearCustomProperties()
426 m_aCustomProperties.clear();
429 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
431 std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
432 m_aCustomProperties.push_back( std::move(pProp) );
436 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
438 m_aCmisProperties = cmisProps;
441 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
443 OUString aValue;
444 sal_Int32 nValue = 0;
445 bool bValue = false;
446 bool bIsInt = false;
447 bool bIsString = false;
448 nMemberId &= ~CONVERT_TWIPS;
449 switch ( nMemberId )
451 case MID_DOCINFO_USEUSERDATA:
452 bValue = IsUseUserData();
453 break;
454 case MID_DOCINFO_USETHUMBNAILSAVE:
455 bValue = IsUseThumbnailSave();
456 break;
457 case MID_DOCINFO_DELETEUSERDATA:
458 bValue = m_bDeleteUserData;
459 break;
460 case MID_DOCINFO_AUTOLOADENABLED:
461 bValue = isAutoloadEnabled();
462 break;
463 case MID_DOCINFO_AUTOLOADSECS:
464 bIsInt = true;
465 nValue = getAutoloadDelay();
466 break;
467 case MID_DOCINFO_AUTOLOADURL:
468 bIsString = true;
469 aValue = getAutoloadURL();
470 break;
471 case MID_DOCINFO_DEFAULTTARGET:
472 bIsString = true;
473 aValue = getDefaultTarget();
474 break;
475 case MID_DOCINFO_DESCRIPTION:
476 bIsString = true;
477 aValue = getDescription();
478 break;
479 case MID_DOCINFO_KEYWORDS:
480 bIsString = true;
481 aValue = getKeywords();
482 break;
483 case MID_DOCINFO_SUBJECT:
484 bIsString = true;
485 aValue = getSubject();
486 break;
487 case MID_DOCINFO_TITLE:
488 bIsString = true;
489 aValue = getTitle();
490 break;
491 default:
492 OSL_FAIL("Wrong MemberId!");
493 return false;
496 if ( bIsString )
497 rVal <<= aValue;
498 else if ( bIsInt )
499 rVal <<= nValue;
500 else
501 rVal <<= bValue;
502 return true;
505 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
507 OUString aValue;
508 sal_Int32 nValue=0;
509 bool bValue = false;
510 bool bRet = false;
511 nMemberId &= ~CONVERT_TWIPS;
512 switch ( nMemberId )
514 case MID_DOCINFO_USEUSERDATA:
515 bRet = (rVal >>= bValue);
516 if ( bRet )
517 SetUseUserData( bValue );
518 break;
519 case MID_DOCINFO_USETHUMBNAILSAVE:
520 bRet = (rVal >>=bValue);
521 if ( bRet )
522 SetUseThumbnailSave( bValue );
523 break;
524 case MID_DOCINFO_DELETEUSERDATA:
525 // QUESTION: deleting user data was done here; seems to be superfluous!
526 bRet = (rVal >>= bValue);
527 if ( bRet )
528 SetDeleteUserData( bValue );
529 break;
530 case MID_DOCINFO_AUTOLOADENABLED:
531 bRet = (rVal >>= bValue);
532 if ( bRet )
533 m_isAutoloadEnabled = bValue;
534 break;
535 case MID_DOCINFO_AUTOLOADSECS:
536 bRet = (rVal >>= nValue);
537 if ( bRet )
538 m_AutoloadDelay = nValue;
539 break;
540 case MID_DOCINFO_AUTOLOADURL:
541 bRet = (rVal >>= aValue);
542 if ( bRet )
543 m_AutoloadURL = aValue;
544 break;
545 case MID_DOCINFO_DEFAULTTARGET:
546 bRet = (rVal >>= aValue);
547 if ( bRet )
548 m_DefaultTarget = aValue;
549 break;
550 case MID_DOCINFO_DESCRIPTION:
551 bRet = (rVal >>= aValue);
552 if ( bRet )
553 setDescription(aValue);
554 break;
555 case MID_DOCINFO_KEYWORDS:
556 bRet = (rVal >>= aValue);
557 if ( bRet )
558 setKeywords(aValue);
559 break;
560 case MID_DOCINFO_SUBJECT:
561 bRet = (rVal >>= aValue);
562 if ( bRet )
563 setSubject(aValue);
564 break;
565 case MID_DOCINFO_TITLE:
566 bRet = (rVal >>= aValue);
567 if ( bRet )
568 setTitle(aValue);
569 break;
570 default:
571 OSL_FAIL("Wrong MemberId!");
572 return false;
575 return bRet;
578 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
579 : SfxTabPage(pPage, pController, "sfx/ui/descriptioninfopage.ui", "DescriptionInfoPage", &rItemSet)
580 , m_pInfoItem(nullptr)
581 , m_xTitleEd(m_xBuilder->weld_entry("title"))
582 , m_xThemaEd(m_xBuilder->weld_entry("subject"))
583 , m_xKeywordsEd(m_xBuilder->weld_entry("keywords"))
584 , m_xCommentEd(m_xBuilder->weld_text_view("comments"))
586 m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
587 m_xCommentEd->get_height_rows(16));
590 SfxDocumentDescPage::~SfxDocumentDescPage()
594 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
596 return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
599 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
601 // Test whether a change is present
602 const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
603 const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
604 const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
605 const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
606 if ( !( bTitleMod || bThemeMod || bKeywordsMod || bCommentMod ) )
608 return false;
611 // Generating the output data
612 const SfxDocumentInfoItem* pItem = nullptr;
613 SfxDocumentInfoItem* pInfo = nullptr;
614 const SfxItemSet* pExSet = GetDialogExampleSet();
616 if ( pExSet && !(pItem = pExSet->GetItemIfSet( SID_DOCINFO )) )
617 pInfo = m_pInfoItem;
618 else if ( pItem )
619 pInfo = new SfxDocumentInfoItem( *pItem );
621 if ( !pInfo )
623 SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
624 return false;
627 if ( bTitleMod )
629 pInfo->setTitle( m_xTitleEd->get_text() );
631 if ( bThemeMod )
633 pInfo->setSubject( m_xThemaEd->get_text() );
635 if ( bKeywordsMod )
637 pInfo->setKeywords( m_xKeywordsEd->get_text() );
639 if ( bCommentMod )
641 pInfo->setDescription( m_xCommentEd->get_text() );
643 rSet->Put( *pInfo );
644 if ( pInfo != m_pInfoItem )
646 delete pInfo;
649 return true;
652 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
654 m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
656 m_xTitleEd->set_text(m_pInfoItem->getTitle());
657 m_xThemaEd->set_text(m_pInfoItem->getSubject());
658 m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
659 m_xCommentEd->set_text(m_pInfoItem->getDescription());
661 m_xTitleEd->save_value();
662 m_xThemaEd->save_value();
663 m_xKeywordsEd->save_value();
664 m_xCommentEd->save_value();
666 const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
667 if (pROItem && pROItem->GetValue())
669 m_xTitleEd->set_editable(false);
670 m_xThemaEd->set_editable(false);
671 m_xKeywordsEd->set_editable(false);
672 m_xCommentEd->set_editable(false);
676 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
677 : SfxTabPage(pPage, pController, "sfx/ui/documentinfopage.ui", "DocumentInfoPage", &rItemSet)
678 , bEnableUseUserData( false )
679 , bHandleDelete( false )
680 , m_xBmp(m_xBuilder->weld_image("icon"))
681 , m_xNameED(m_xBuilder->weld_label("nameed"))
682 , m_xChangePassBtn(m_xBuilder->weld_button("changepass"))
683 , m_xShowTypeFT(m_xBuilder->weld_label("showtype"))
684 , m_xFileValEd(m_xBuilder->weld_link_button("showlocation"))
685 , m_xShowSizeFT(m_xBuilder->weld_label("showsize"))
686 , m_xCreateValFt(m_xBuilder->weld_label("showcreate"))
687 , m_xChangeValFt(m_xBuilder->weld_label("showmodify"))
688 , m_xSignedValFt(m_xBuilder->weld_label("showsigned"))
689 , m_xSignatureBtn(m_xBuilder->weld_button("signature"))
690 , m_xPrintValFt(m_xBuilder->weld_label("showprint"))
691 , m_xTimeLogValFt(m_xBuilder->weld_label("showedittime"))
692 , m_xDocNoValFt(m_xBuilder->weld_label("showrevision"))
693 , m_xUseUserDataCB(m_xBuilder->weld_check_button("userdatacb"))
694 , m_xDeleteBtn(m_xBuilder->weld_button("reset"))
695 , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button("thumbnailsavecb"))
696 , m_xTemplFt(m_xBuilder->weld_label("templateft"))
697 , m_xTemplValFt(m_xBuilder->weld_label("showtemplate"))
698 , m_xImagePreferredDpiCheckButton(m_xBuilder->weld_check_button("image-preferred-dpi-checkbutton"))
699 , m_xImagePreferredDpiComboBox(m_xBuilder->weld_combo_box("image-preferred-dpi-combobox"))
701 m_xUseUserDataCB->set_accessible_description(SfxResId(STR_A11Y_DESC_USERDATA));
703 m_aUnknownSize = m_xShowSizeFT->get_label();
704 m_xShowSizeFT->set_label(OUString());
706 m_aMultiSignedStr = m_xSignedValFt->get_label();
707 m_xSignedValFt->set_label(OUString());
709 ImplUpdateSignatures();
710 ImplCheckPasswordState();
711 m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
712 m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
713 if (comphelper::LibreOfficeKit::isActive())
714 m_xSignatureBtn->hide();
715 m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
716 m_xImagePreferredDpiCheckButton->connect_toggled(LINK(this, SfxDocumentPage, ImagePreferredDPICheckBoxClicked));
718 // [i96288] Check if the document signature command is enabled
719 // on the main list enable/disable the pushbutton accordingly
720 SvtCommandOptions aCmdOptions;
721 if ( aCmdOptions.LookupDisabled( "Signature" ) )
722 m_xSignatureBtn->set_sensitive(false);
725 SfxDocumentPage::~SfxDocumentPage()
727 if (m_xPasswordDialog)
729 m_xPasswordDialog->Response(RET_CANCEL);
730 m_xPasswordDialog.clear();
734 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
736 OUString aName;
737 if (bEnableUseUserData && m_xUseUserDataCB->get_active())
738 aName = SvtUserOptions().GetFullName();
739 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
740 DateTime now( DateTime::SYSTEM );
741 util::DateTime uDT( now.GetUNODateTime() );
742 m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
743 m_xChangeValFt->set_label( "" );
744 m_xPrintValFt->set_label( "" );
745 const tools::Time aTime( 0 );
746 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aTime ) );
747 m_xDocNoValFt->set_label(OUString('1'));
748 bHandleDelete = true;
751 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
753 SfxObjectShell* pDoc = SfxObjectShell::Current();
754 if( pDoc )
756 pDoc->SignDocumentContent(GetFrameWeld());
758 ImplUpdateSignatures();
762 IMPL_LINK_NOARG(SfxDocumentPage, ImagePreferredDPICheckBoxClicked, weld::Toggleable&, void)
764 bool bEnabled = m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE;
765 m_xImagePreferredDpiComboBox->set_sensitive(bEnabled);
768 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
770 SfxObjectShell* pShell = SfxObjectShell::Current();
773 if (!pShell)
774 break;
775 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
776 if (!pMedSet)
777 break;
778 std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
779 if (!pFilter)
780 break;
781 if (comphelper::LibreOfficeKit::isActive())
783 // MS Types support max len of 15 characters while OOXML is "unlimited"
784 const sal_uInt16 maxPwdLen = sfx2::IsMSType(pFilter) && !sfx2::IsOOXML(pFilter) ? 15 : 0;
785 // handle the pwd dialog asynchronously
786 VclAbstractDialogFactory * pFact = VclAbstractDialogFactory::Create();
787 m_xPasswordDialog = pFact->CreatePasswordToOpenModifyDialog(GetFrameWeld(), maxPwdLen, false);
788 m_xPasswordDialog->AllowEmpty(); // needed to remove password
789 m_xPasswordDialog->StartExecuteAsync([this, pFilter, pMedSet, pShell](sal_Int32 nResult)
791 if (nResult == RET_OK)
793 sfx2::SetPassword(pFilter, pMedSet, m_xPasswordDialog->GetPasswordToOpen(),
794 m_xPasswordDialog->GetPasswordToOpen(), true);
795 pShell->SetModified();
797 m_xPasswordDialog->disposeOnce();
799 } else {
800 sfx2::RequestPassword(pFilter, OUString(), pMedSet, GetFrameWeld()->GetXWindow());
801 pShell->SetModified();
804 while (false);
807 void SfxDocumentPage::ImplUpdateSignatures()
809 SfxObjectShell* pDoc = SfxObjectShell::Current();
810 if ( !pDoc )
811 return;
813 SfxMedium* pMedium = pDoc->GetMedium();
814 if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
815 return;
817 Reference< security::XDocumentDigitalSignatures > xD;
820 xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
821 xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
823 catch ( const css::uno::DeploymentException& )
826 OUString s;
827 Sequence< security::DocumentSignatureInformation > aInfos;
829 if ( xD.is() )
830 aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
831 uno::Reference< io::XInputStream >() );
832 if ( aInfos.getLength() > 1 )
833 s = m_aMultiSignedStr;
834 else if ( aInfos.getLength() == 1 )
836 const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
837 s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
838 comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
840 m_xSignedValFt->set_label(s);
843 void SfxDocumentPage::ImplCheckPasswordState()
845 SfxObjectShell* pShell = SfxObjectShell::Current();
848 if (!pShell)
849 break;
850 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
851 if (!pMedSet)
852 break;
853 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pMedSet, SID_ENCRYPTIONDATA, false);
854 uno::Sequence< beans::NamedValue > aEncryptionData;
855 if (pEncryptionDataItem)
856 pEncryptionDataItem->GetValue() >>= aEncryptionData;
857 else
858 break;
860 if (!aEncryptionData.hasElements())
861 break;
862 m_xChangePassBtn->set_sensitive(true);
863 return;
865 while (false);
866 m_xChangePassBtn->set_sensitive(comphelper::LibreOfficeKit::isActive());
869 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
871 return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
874 void SfxDocumentPage::EnableUseUserData()
876 bEnableUseUserData = true;
877 m_xUseUserDataCB->show();
878 m_xDeleteBtn->show();
881 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
883 bool bRet = false;
885 if ( !bHandleDelete && bEnableUseUserData &&
886 m_xUseUserDataCB->get_state_changed_from_saved() )
888 const SfxItemSet* pExpSet = GetDialogExampleSet();
889 const SfxDocumentInfoItem* pInfoItem;
891 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO ) ) )
893 bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
894 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
895 rSet->Put( *pInfoItem );
896 bRet = true;
900 if ( bHandleDelete )
902 const SfxItemSet* pExpSet = GetDialogExampleSet();
903 const SfxDocumentInfoItem* pInfoItem;
904 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
906 bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
907 SfxDocumentInfoItem newItem( *pInfoItem );
908 newItem.resetUserData( bUseAuthor
909 ? SvtUserOptions().GetFullName()
910 : OUString() );
911 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
912 newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
914 newItem.SetDeleteUserData( true );
915 rSet->Put( newItem );
916 bRet = true;
920 if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
922 const SfxItemSet* pExpSet = GetDialogExampleSet();
923 const SfxDocumentInfoItem* pInfoItem;
925 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
927 bool bUseThumbnail = ( TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state() );
928 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave( bUseThumbnail );
929 rSet->Put( *pInfoItem );
930 bRet = true;
934 SfxObjectShell* pDocSh = SfxObjectShell::Current();
935 if (pDocSh)
937 uno::Reference<lang::XMultiServiceFactory> xFac(pDocSh->GetModel(), uno::UNO_QUERY);
938 if (xFac.is())
940 uno::Reference<beans::XPropertySet> xProps(xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY);
941 if (xProps.is())
943 sal_Int32 nImagePreferredDPI = 0;
944 if (m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE)
946 OUString aImagePreferredDPIString = m_xImagePreferredDpiComboBox->get_active_text();
947 nImagePreferredDPI = aImagePreferredDPIString.toInt32();
949 xProps->setPropertyValue("ImagePreferredDPI", uno::Any(nImagePreferredDPI));
954 return bRet;
957 void SfxDocumentPage::Reset( const SfxItemSet* rSet )
959 // Determine the document information
960 const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
962 // template data
963 if (rInfoItem.HasTemplate())
965 const OUString& rName = rInfoItem.getTemplateName();
966 if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
967 m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
968 else
969 m_xTemplValFt->set_label(rName);
971 else
973 m_xTemplFt->hide();
974 m_xTemplValFt->hide();
977 // determine file name
978 OUString aFile( rInfoItem.GetValue() );
979 OUString aFactory( aFile );
980 if ( aFile.getLength() > 2 && aFile[0] == '[' )
982 sal_Int32 nPos = aFile.indexOf( ']' );
983 aFactory = aFile.copy( 1, nPos-1 );
984 aFile = aFile.copy( nPos+1 );
987 // determine name
988 INetURLObject aURL(aFile);
989 OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
990 if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
991 aName = SfxResId( STR_NONAME );
992 m_xNameED->set_label( aName );
994 // determine context symbol
995 aURL.SetSmartProtocol( INetProtocol::File );
996 aURL.SetSmartURL( aFactory);
997 const OUString& rMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
998 OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
999 m_xBmp->set_from_icon_name(aImage);
1001 // determine size and type
1002 OUString aSizeText( m_aUnknownSize );
1003 if ( aURL.GetProtocol() == INetProtocol::File ||
1004 aURL.isAnyKnownWebDAVScheme() )
1005 aSizeText = CreateSizeText( SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
1006 m_xShowSizeFT->set_label( aSizeText );
1008 OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(rMainURL) );
1009 if ( aDescription.isEmpty() )
1010 aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
1011 m_xShowTypeFT->set_label( aDescription );
1013 // determine location
1014 // online we don't know file location so we just set it as the name
1015 if (comphelper::LibreOfficeKit::isActive())
1017 m_xFileValEd->set_label(aName);
1018 m_xFileValEd->set_uri(aName);
1020 else
1022 aURL.SetSmartURL( aFile);
1023 if ( aURL.GetProtocol() == INetProtocol::File )
1025 INetURLObject aPath( aURL );
1026 aPath.setFinalSlash();
1027 aPath.removeSegment();
1028 // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
1029 aPath.removeFinalSlash();
1030 OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
1031 m_xFileValEd->set_label(aText);
1032 OUString aURLStr;
1033 osl::FileBase::getFileURLFromSystemPath(aText, aURLStr);
1034 m_xFileValEd->set_uri(aURLStr);
1036 else if (aURL.GetProtocol() != INetProtocol::PrivSoffice)
1038 m_xFileValEd->set_label(aURL.GetPartBeforeLastName());
1039 m_xFileValEd->set_uri(m_xFileValEd->get_label());
1044 // handle access data
1045 bool bUseUserData = rInfoItem.IsUseUserData();
1046 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
1047 m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
1048 rInfoItem.getCreationDate(), rLocaleWrapper ) );
1049 util::DateTime aTime( rInfoItem.getModificationDate() );
1050 if ( aTime.Month > 0 )
1051 m_xChangeValFt->set_label( ConvertDateTime_Impl(
1052 rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
1053 aTime = rInfoItem.getPrintDate();
1054 if ( aTime.Month > 0 )
1055 m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
1056 aTime, rLocaleWrapper ) );
1057 const tools::Long nTime = rInfoItem.getEditingDuration();
1058 if ( bUseUserData )
1060 const tools::Time aT( nTime/3600, (nTime%3600)/60, nTime%60 );
1061 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aT ) );
1062 m_xDocNoValFt->set_label( OUString::number(
1063 rInfoItem.getEditingCycles() ) );
1066 bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1068 // Check for cmis properties where otherwise unavailable
1069 if ( rInfoItem.isCmisDocument( ) )
1071 const uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
1072 for ( const auto& rCmisProp : aCmisProps )
1074 if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1075 aSizeText == m_aUnknownSize )
1077 Sequence< sal_Int64 > seqValue;
1078 rCmisProp.Value >>= seqValue;
1079 SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1080 Application::GetSettings().GetLanguageTag().getLanguageType() );
1081 sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1082 if ( seqValue.hasElements() )
1084 OUString sValue;
1085 aNumberFormatter.GetInputLineString( seqValue[0], nIndex, sValue );
1086 m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1090 util::DateTime uDT;
1091 OUString emptyDate = ConvertDateTime_Impl( u"", uDT, rLocaleWrapper );
1092 if ( rCmisProp.Id == "cmis:creationDate" &&
1093 (m_xCreateValFt->get_label() == emptyDate ||
1094 m_xCreateValFt->get_label().isEmpty()))
1096 Sequence< util::DateTime > seqValue;
1097 rCmisProp.Value >>= seqValue;
1098 if ( seqValue.hasElements() )
1100 m_xCreateValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1103 if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1104 (m_xChangeValFt->get_label() == emptyDate ||
1105 m_xChangeValFt->get_label().isEmpty()))
1107 Sequence< util::DateTime > seqValue;
1108 rCmisProp.Value >>= seqValue;
1109 if ( seqValue.hasElements() )
1111 m_xChangeValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1117 m_xUseUserDataCB->set_active(bUseUserData);
1118 m_xUseUserDataCB->save_state();
1119 m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1120 bHandleDelete = false;
1121 m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1122 m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1123 m_xUseThumbnailSaveCB->save_state();
1125 SfxObjectShell* pDocSh = SfxObjectShell::Current();
1126 sal_Int32 nImagePreferredDPI = 0;
1127 if (pDocSh)
1131 uno::Reference< lang::XMultiServiceFactory > xFac( pDocSh->GetModel(), uno::UNO_QUERY_THROW );
1132 uno::Reference< beans::XPropertySet > xProps( xFac->createInstance("com.sun.star.document.Settings"), uno::UNO_QUERY_THROW );
1134 xProps->getPropertyValue("ImagePreferredDPI") >>= nImagePreferredDPI;
1136 catch( uno::Exception& )
1140 if (nImagePreferredDPI > 0)
1142 m_xImagePreferredDpiCheckButton->set_state(TRISTATE_TRUE);
1143 m_xImagePreferredDpiComboBox->set_sensitive(true);
1144 m_xImagePreferredDpiComboBox->set_entry_text(OUString::number(nImagePreferredDPI));
1146 else
1148 m_xImagePreferredDpiCheckButton->set_state(TRISTATE_FALSE);
1149 m_xImagePreferredDpiComboBox->set_sensitive(false);
1150 m_xImagePreferredDpiComboBox->set_entry_text("");
1155 SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1156 : SfxTabDialogController(pParent, "sfx/ui/documentpropertiesdialog.ui",
1157 "DocumentPropertiesDialog", &rItemSet)
1159 const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1161 #ifdef DBG_UTIL
1162 const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1163 DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1164 #endif
1166 // Determine the Titles
1167 OUString aTitle(m_xDialog->get_title());
1168 const SfxStringItem* pItem = rItemSet.GetItemIfSet( SID_EXPLORER_PROPS_START, false );
1169 if ( !pItem )
1171 // File name
1172 const OUString& aFile( rInfoItem.GetValue() );
1174 INetURLObject aURL;
1175 aURL.SetSmartProtocol( INetProtocol::File );
1176 aURL.SetSmartURL( aFile);
1177 if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1179 OUString aLastName( aURL.GetLastName() );
1180 if ( !aLastName.isEmpty() )
1181 aTitle = aTitle.replaceFirst("%1", aLastName);
1182 else
1183 aTitle = aTitle.replaceFirst("%1", aFile);
1185 else
1186 aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1188 else
1190 aTitle = aTitle.replaceFirst("%1", pItem->GetValue());
1192 m_xDialog->set_title(aTitle);
1194 // Property Pages
1195 AddTabPage("general", SfxDocumentPage::Create, nullptr);
1196 AddTabPage("description", SfxDocumentDescPage::Create, nullptr);
1198 if (!comphelper::LibreOfficeKit::isActive())
1199 AddTabPage("customprops", SfxCustomPropertiesPage::Create, nullptr);
1200 else
1201 RemoveTabPage("customprops");
1203 if (rInfoItem.isCmisDocument())
1204 AddTabPage("cmisprops", SfxCmisPropertiesPage::Create, nullptr);
1205 else
1206 RemoveTabPage("cmisprops");
1207 // Disable security page for online as not fully asynced yet
1208 if (!comphelper::LibreOfficeKit::isActive())
1209 AddTabPage("security", SfxSecurityPage::Create, nullptr);
1210 else
1211 RemoveTabPage("security");
1214 void SfxDocumentInfoDialog::PageCreated(const OUString& rId, SfxTabPage &rPage)
1216 if (rId == "general")
1217 static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1220 void SfxDocumentInfoDialog::AddFontTabPage()
1222 AddTabPage("font", SfxResId(STR_FONT_TABPAGE), SfxDocumentFontsPage::Create);
1225 // class CustomPropertiesYesNoButton -------------------------------------
1227 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1228 std::unique_ptr<weld::RadioButton> xYesButton,
1229 std::unique_ptr<weld::RadioButton> xNoButton)
1230 : m_xTopLevel(std::move(xTopLevel))
1231 , m_xYesButton(std::move(xYesButton))
1232 , m_xNoButton(std::move(xNoButton))
1234 CheckNo();
1237 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1242 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1243 : GenericDialogController(pParent, "sfx/ui/editdurationdialog.ui", "EditDurationDialog")
1244 , m_xNegativeCB(m_xBuilder->weld_check_button("negative"))
1245 , m_xYearNF(m_xBuilder->weld_spin_button("years"))
1246 , m_xMonthNF(m_xBuilder->weld_spin_button("months"))
1247 , m_xDayNF(m_xBuilder->weld_spin_button("days"))
1248 , m_xHourNF(m_xBuilder->weld_spin_button("hours"))
1249 , m_xMinuteNF(m_xBuilder->weld_spin_button("minutes"))
1250 , m_xSecondNF(m_xBuilder->weld_spin_button("seconds"))
1251 , m_xMSecondNF(m_xBuilder->weld_spin_button("milliseconds"))
1253 m_xNegativeCB->set_active(rDuration.Negative);
1254 m_xYearNF->set_value(rDuration.Years);
1255 m_xMonthNF->set_value(rDuration.Months);
1256 m_xDayNF->set_value(rDuration.Days);
1257 m_xHourNF->set_value(rDuration.Hours);
1258 m_xMinuteNF->set_value(rDuration.Minutes);
1259 m_xSecondNF->set_value(rDuration.Seconds);
1260 m_xMSecondNF->set_value(rDuration.NanoSeconds);
1263 util::Duration DurationDialog_Impl::GetDuration() const
1265 util::Duration aRet;
1266 aRet.Negative = m_xNegativeCB->get_active();
1267 aRet.Years = m_xYearNF->get_value();
1268 aRet.Months = m_xMonthNF->get_value();
1269 aRet.Days = m_xDayNF->get_value();
1270 aRet.Hours = m_xHourNF->get_value();
1271 aRet.Minutes = m_xMinuteNF->get_value();
1272 aRet.Seconds = m_xSecondNF->get_value();
1273 aRet.NanoSeconds = m_xMSecondNF->get_value();
1274 return aRet;
1277 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1278 std::unique_ptr<weld::Button> xEditButton)
1279 : m_xEntry(std::move(xEntry))
1280 , m_xEditButton(std::move(xEditButton))
1282 m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1283 SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1286 void CustomPropertiesDurationField::set_visible(bool bVisible)
1288 m_xEntry->set_visible(bVisible);
1289 m_xEditButton->set_visible(bVisible);
1292 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1294 m_aDuration = rDuration;
1295 OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1296 SfxResId(SFX_ST_DURATION_FORMAT);
1297 sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1298 sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1299 sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days ) );
1300 sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours ) );
1301 sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1302 sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1303 m_xEntry->set_text(sText);
1306 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1308 m_xDurationDialog = std::make_shared<DurationDialog_Impl>(&rButton, GetDuration());
1309 weld::DialogController::runAsync(m_xDurationDialog, [&](sal_Int32 response)
1311 if (response == RET_OK)
1313 SetDuration(m_xDurationDialog->GetDuration());
1318 CustomPropertiesDurationField::~CustomPropertiesDurationField()
1320 if (m_xDurationDialog)
1321 m_xDurationDialog->response(RET_CANCEL);
1324 namespace
1326 void fillNameBox(weld::ComboBox& rNameBox)
1328 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1329 rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1330 Size aSize(rNameBox.get_preferred_size());
1331 rNameBox.set_size_request(aSize.Width(), aSize.Height());
1334 void fillTypeBox(weld::ComboBox& rTypeBox)
1336 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1338 OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1339 rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1341 rTypeBox.set_active(0);
1342 Size aSize(rTypeBox.get_preferred_size());
1343 rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1347 // struct CustomPropertyLine ---------------------------------------------
1348 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1349 : m_pParent(pParent)
1350 , m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/linefragment.ui"))
1351 , m_xLine(m_xBuilder->weld_container("lineentry"))
1352 , m_xNameBox(m_xBuilder->weld_combo_box("namebox"))
1353 , m_xTypeBox(m_xBuilder->weld_combo_box("typebox"))
1354 , m_xValueEdit(m_xBuilder->weld_entry("valueedit"))
1355 , m_xDateTimeBox(m_xBuilder->weld_widget("datetimebox"))
1356 , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date"))))
1357 , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button("time")))
1358 , m_xDurationBox(m_xBuilder->weld_widget("durationbox"))
1359 , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry("duration"),
1360 m_xBuilder->weld_button("durationbutton")))
1361 , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget("yesno"),
1362 m_xBuilder->weld_radio_button("yes"),
1363 m_xBuilder->weld_radio_button("no")))
1364 , m_xRemoveButton(m_xBuilder->weld_button("remove"))
1365 , m_bTypeLostFocus( false )
1367 fillNameBox(*m_xNameBox);
1368 fillTypeBox(*m_xTypeBox);
1370 m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1371 m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1372 m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1373 //add lose focus handlers of date/time fields
1374 m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1377 void CustomPropertyLine::Clear()
1379 m_xNameBox->set_active(-1);
1380 m_xValueEdit->set_text(OUString());
1384 void CustomPropertyLine::Hide()
1386 m_xLine->hide();
1389 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1390 weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1391 : m_nHeight(0)
1392 , m_nLineHeight(0)
1393 , m_nScrollPos(0)
1394 , m_pCurrentLine(nullptr)
1395 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1396 Application::GetSettings().GetLanguageTag().getLanguageType())
1397 , m_aEditLoseFocusIdle("sfx2 CustomPropertiesWindow loseFocusIdle")
1398 , m_aBoxLoseFocusIdle("sfx2 CustomPropertiesWindow m_aBoxLoseFocusIdle")
1399 , m_rBody(rParent)
1400 , m_rHeaderAccName(rHeaderAccName)
1401 , m_rHeaderAccType(rHeaderAccType)
1402 , m_rHeaderAccValue(rHeaderAccValue)
1404 m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1405 m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1406 m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1407 m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1410 CustomPropertiesWindow::~CustomPropertiesWindow()
1412 m_aEditLoseFocusIdle.Stop();
1413 m_aBoxLoseFocusIdle.Stop();
1415 m_pCurrentLine = nullptr;
1418 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1420 auto nType = rBox.get_active_id().toInt32();
1421 m_xValueEdit->set_visible( (Custom_Type_Text == nType) || (Custom_Type_Number == nType) );
1422 m_xDateTimeBox->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1423 m_xDateField->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1424 m_xTimeField->set_visible( Custom_Type_Datetime == nType );
1425 m_xDurationBox->set_visible( Custom_Type_Duration == nType );
1426 m_xDurationField->set_visible( Custom_Type_Duration == nType );
1427 m_xYesNoButton->set_visible( Custom_Type_Boolean == nType );
1430 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1432 DoTypeHdl(rBox);
1435 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1437 StoreCustomProperties();
1439 auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1440 [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1441 if ( pFound != m_aCustomPropertiesLines.end() )
1443 sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1444 sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1445 m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1447 ReloadLinesContent();
1450 m_aRemovedHdl.Call(nullptr);
1453 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1455 m_pParent->Remove(this);
1458 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1460 m_pCurrentLine = pLine;
1461 m_aEditLoseFocusIdle.Start();
1464 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1466 if (!m_bTypeLostFocus)
1467 m_pParent->EditLoseFocus(this);
1468 else
1469 m_bTypeLostFocus = false;
1472 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1474 m_pCurrentLine = pLine;
1475 m_aBoxLoseFocusIdle.Start();
1478 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1480 m_pParent->BoxLoseFocus(this);
1483 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1485 ValidateLine( m_pCurrentLine, false );
1488 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1490 ValidateLine( m_pCurrentLine, true );
1493 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1495 bool bIsValid = true;
1496 pLine->m_bTypeLostFocus = false;
1497 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1498 OUString sValue = pLine->m_xValueEdit->get_text();
1499 if ( sValue.isEmpty() )
1500 return true;
1502 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1503 if ( Custom_Type_Number == nType )
1504 // tdf#116214 Scientific format allows to use also standard numbers
1505 nIndex = const_cast< SvNumberFormatter& >(
1506 m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1507 else if ( Custom_Type_Date == nType )
1508 nIndex = const_cast< SvNumberFormatter& >(
1509 m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1511 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1513 sal_uInt32 nTemp = nIndex;
1514 double fDummy = 0.0;
1515 bIsValid = const_cast< SvNumberFormatter& >(
1516 m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1517 if ( bIsValid && nTemp != nIndex )
1518 // sValue is a number but the format doesn't match the index
1519 bIsValid = false;
1522 return bIsValid;
1525 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1527 if (pLine && !IsLineValid(pLine))
1529 if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1530 pLine->m_bTypeLostFocus = true;
1531 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1532 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1533 if (xMessageBox->run() == RET_OK)
1534 pLine->m_xTypeBox->set_active_id(OUString::number(Custom_Type_Text));
1535 else
1536 pLine->m_xValueEdit->grab_focus();
1540 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1542 while (GetExistingLineCount() < nCount)
1544 CreateNewLine();
1548 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1550 m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1551 ReloadLinesContent();
1554 void CustomPropertiesWindow::CreateNewLine()
1556 CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1557 pNewLine->m_xNameBox->set_accessible_relation_labeled_by(&m_rHeaderAccName);
1558 pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1559 pNewLine->m_xTypeBox->set_accessible_relation_labeled_by(&m_rHeaderAccType);
1560 pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1561 pNewLine->m_xValueEdit->set_accessible_relation_labeled_by(&m_rHeaderAccValue);
1562 pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1564 m_aCustomPropertiesLines.emplace_back( pNewLine );
1566 // this breaks online's jsdialogbuilder
1567 if (!comphelper::LibreOfficeKit::isActive()){
1568 // for ui-testing. Distinguish the elements in the lines
1569 sal_uInt16 nSize = m_aCustomPropertiesLines.size();
1570 pNewLine->m_xNameBox->set_buildable_name(
1571 pNewLine->m_xNameBox->get_buildable_name() + OUString::number(nSize));
1572 pNewLine->m_xTypeBox->set_buildable_name(
1573 pNewLine->m_xTypeBox->get_buildable_name() + OUString::number(nSize));
1574 pNewLine->m_xValueEdit->set_buildable_name(
1575 pNewLine->m_xValueEdit->get_buildable_name() + OUString::number(nSize));
1576 pNewLine->m_xRemoveButton->set_buildable_name(
1577 pNewLine->m_xRemoveButton->get_buildable_name() + OUString::number(nSize));
1580 pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1583 bool CustomPropertiesWindow::AreAllLinesValid() const
1585 bool bRet = true;
1586 for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1588 if ( !IsLineValid( pLine.get() ) )
1590 bRet = false;
1591 break;
1595 return bRet;
1598 void CustomPropertiesWindow::ClearAllLines()
1600 for (auto& pLine : m_aCustomPropertiesLines)
1602 pLine->Clear();
1604 m_pCurrentLine = nullptr;
1605 m_aCustomProperties.clear();
1606 m_nScrollPos = 0;
1609 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1611 StoreCustomProperties();
1612 m_nScrollPos += nNewPos;
1613 ReloadLinesContent();
1616 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1618 StoreCustomProperties();
1620 Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1621 std::transform(
1622 m_aCustomProperties.begin(), m_aCustomProperties.end(), aPropertiesSeq.getArray(),
1623 [](const auto& el) { return comphelper::makePropertyValue(el->m_sName, el->m_aValue); });
1625 return aPropertiesSeq;
1628 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1629 : m_xTimeField(std::move(xTimeField))
1630 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1631 , m_isUTC(false)
1633 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1634 m_xFormatter->EnableEmptyField(false);
1637 tools::Time CustomPropertiesTimeField::get_value() const
1639 return m_xFormatter->GetTime();
1642 void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1644 m_xFormatter->SetTime(rTime);
1647 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1651 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1652 : m_xDateField(pDateField)
1654 DateTime aDateTime(DateTime::SYSTEM);
1655 m_xDateField->set_date(aDateTime);
1658 void CustomPropertiesDateField::set_visible(bool bVisible)
1660 m_xDateField->set_visible(bVisible);
1663 Date CustomPropertiesDateField::get_date() const
1665 return m_xDateField->get_date();
1668 void CustomPropertiesDateField::set_date(const Date& rDate)
1670 m_xDateField->set_date(rDate);
1673 CustomPropertiesDateField::~CustomPropertiesDateField()
1677 void CustomPropertiesWindow::StoreCustomProperties()
1679 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1681 for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1683 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1685 OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1686 if (!sPropertyName.isEmpty())
1688 m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1689 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1690 if (Custom_Type_Number == nType)
1692 double nValue = 0;
1693 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1694 bool bIsNum = m_aNumberFormatter.
1695 IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1696 if (bIsNum)
1697 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1699 else if (Custom_Type_Boolean == nType)
1701 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1702 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1704 else if (Custom_Type_Datetime == nType)
1706 Date aTmpDate = pLine->m_xDateField->get_date();
1707 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1708 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1709 aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1710 aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1711 pLine->m_xTimeField->m_isUTC);
1712 if (pLine->m_xDateField->m_TZ)
1714 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1715 aDateTime, *pLine->m_xDateField->m_TZ);
1717 else
1719 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1722 else if (Custom_Type_Date == nType)
1724 Date aTmpDate = pLine->m_xDateField->get_date();
1725 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1726 aTmpDate.GetYear());
1727 if (pLine->m_xDateField->m_TZ)
1729 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1730 aDate, *pLine->m_xDateField->m_TZ);
1732 else
1734 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1737 else if (Custom_Type_Duration == nType)
1739 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1741 else
1743 OUString sValue(pLine->m_xValueEdit->get_text());
1744 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1750 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1752 m_aCustomProperties = std::move(rProperties);
1753 ReloadLinesContent();
1756 void CustomPropertiesWindow::ReloadLinesContent()
1758 double nTmpValue = 0;
1759 bool bTmpValue = false;
1760 OUString sTmpValue;
1761 util::DateTime aTmpDateTime;
1762 util::Date aTmpDate;
1763 util::DateTimeWithTimezone aTmpDateTimeTZ;
1764 util::DateWithTimezone aTmpDateTZ;
1765 util::Duration aTmpDuration;
1766 SvtSysLocale aSysLocale;
1767 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1768 CustomProperties nType = Custom_Type_Unknown;
1769 OUString sValue;
1771 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1772 sal_uInt32 i = 0;
1774 for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1776 const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1777 const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1779 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1780 pLine->Clear();
1782 pLine->m_xNameBox->set_entry_text(rName);
1783 pLine->m_xLine->show();
1785 if (!rAny.hasValue())
1787 pLine->m_xValueEdit->set_text(OUString());
1789 else if (rAny >>= nTmpValue)
1791 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1792 m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex, sValue);
1793 pLine->m_xValueEdit->set_text(sValue);
1794 nType = Custom_Type_Number;
1796 else if (rAny >>= bTmpValue)
1798 sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1799 nType = Custom_Type_Boolean;
1801 else if (rAny >>= sTmpValue)
1803 pLine->m_xValueEdit->set_text(sTmpValue);
1804 nType = Custom_Type_Text;
1806 else if (rAny >>= aTmpDate)
1808 pLine->m_xDateField->set_date(Date(aTmpDate));
1809 nType = Custom_Type_Date;
1811 else if (rAny >>= aTmpDateTime)
1813 pLine->m_xDateField->set_date(Date(aTmpDateTime));
1814 pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1815 pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1816 nType = Custom_Type_Datetime;
1818 else if (rAny >>= aTmpDateTZ)
1820 pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1821 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1822 pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1823 nType = Custom_Type_Date;
1826 else if (rAny >>= aTmpDateTimeTZ)
1828 util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1829 pLine->m_xDateField->set_date(Date(rDT));
1830 pLine->m_xTimeField->set_value(tools::Time(rDT));
1831 pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1832 pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1833 nType = Custom_Type_Datetime;
1835 else if (rAny >>= aTmpDuration)
1837 nType = Custom_Type_Duration;
1838 pLine->m_xDurationField->SetDuration(aTmpDuration);
1841 if (Custom_Type_Boolean == nType)
1843 if (bTmpValue)
1844 pLine->m_xYesNoButton->CheckYes();
1845 else
1846 pLine->m_xYesNoButton->CheckNo();
1848 pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1850 pLine->DoTypeHdl(*pLine->m_xTypeBox);
1853 // tdf#132667 - grab focus on the last inserted property
1854 if (i > 0 && m_aCustomProperties[nDataModelPos + i - 1]->m_sName.isEmpty())
1856 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i - 1].get();
1857 pLine->m_xNameBox->grab_focus();
1860 while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1862 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1863 pLine->Hide();
1864 i++;
1868 CustomPropertiesControl::CustomPropertiesControl()
1869 : m_nThumbPos(0)
1873 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
1875 m_xBox = rBuilder.weld_widget("box");
1876 m_xBody = rBuilder.weld_container("properties");
1878 m_xName = rBuilder.weld_label("name");
1879 m_xType = rBuilder.weld_label("type");
1880 m_xValue = rBuilder.weld_label("value");
1881 m_xVertScroll = rBuilder.weld_scrolled_window("scroll", true);
1882 m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
1884 m_xBox->set_stack_background();
1885 m_xVertScroll->show();
1887 std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
1888 Size aLineSize(xNewLine->m_xLine->get_preferred_size());
1889 m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
1890 m_xBody->set_size_request(aLineSize.Width() + 6, -1);
1891 auto nHeight = aLineSize.Height() * 8;
1892 m_xVertScroll->set_size_request(-1, nHeight + 6);
1894 m_xPropertiesWin->SetHeight(nHeight);
1895 m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
1897 m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
1898 m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
1899 m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
1901 m_xBody->move(xNewLine->m_xLine.get(), nullptr);
1902 xNewLine.reset();
1904 m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
1906 m_xVertScroll->vadjustment_set_lower(0);
1907 m_xVertScroll->vadjustment_set_upper(0);
1908 m_xVertScroll->vadjustment_set_page_size(0xFFFF);
1910 Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
1911 m_xVertScroll->connect_vadjustment_changed(aScrollLink);
1913 ResizeHdl(Size(-1, nHeight));
1916 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
1918 int nHeight = rSize.Height() - 6;
1919 if (nHeight == m_xPropertiesWin->GetHeight())
1920 return;
1921 m_xPropertiesWin->SetHeight(nHeight);
1922 sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
1923 sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
1924 m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
1925 m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
1926 m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
1927 m_xPropertiesWin->ReloadLinesContent();
1930 CustomPropertiesControl::~CustomPropertiesControl()
1934 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
1936 sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
1937 int nThumbPos = rScrollBar.vadjustment_get_value();
1938 nOffset *= ( m_nThumbPos - nThumbPos );
1939 m_nThumbPos = nThumbPos;
1940 m_xPropertiesWin->DoScroll( nOffset );
1943 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
1945 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1946 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1947 if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
1949 m_xVertScroll->vadjustment_set_value(nLineCount - 1);
1950 ScrollHdl(*m_xVertScroll);
1954 void CustomPropertiesControl::AddLine( Any const & rAny )
1956 m_xPropertiesWin->AddLine( OUString(), rAny );
1957 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1958 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1959 if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
1961 m_xVertScroll->vadjustment_set_value(nLineCount + 1);
1962 ScrollHdl(*m_xVertScroll);
1966 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1968 m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
1969 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1970 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1973 // class SfxCustomPropertiesPage -----------------------------------------
1974 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
1975 : SfxTabPage(pPage, pController, "sfx/ui/custominfopage.ui", "CustomInfoPage", &rItemSet)
1976 , m_xPropertiesCtrl(new CustomPropertiesControl)
1977 , m_xAdd(m_xBuilder->weld_button("add"))
1979 m_xPropertiesCtrl->Init(*m_xBuilder);
1980 m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
1983 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
1985 m_xPropertiesCtrl.reset();
1988 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
1990 // tdf#115853: reload current lines before adding a brand new one
1991 // indeed the info are deleted by ClearCustomProperties
1992 // each time SfxDocumentInfoItem destructor is called
1993 SfxDocumentInfoItem pInfo;
1994 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1995 for ( const auto& rProperty : aPropertySeq )
1997 if ( !rProperty.Name.isEmpty() )
1999 pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
2003 Any aAny;
2004 m_xPropertiesCtrl->AddLine(aAny);
2007 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
2009 const SfxDocumentInfoItem* pItem = nullptr;
2010 SfxDocumentInfoItem* pInfo = nullptr;
2011 bool bMustDelete = false;
2013 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2015 pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2016 if (!pItem)
2017 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2018 else
2020 bMustDelete = true;
2021 pInfo = new SfxDocumentInfoItem( *pItem );
2025 if ( pInfo )
2027 // If it's a CMIS document, we can't save custom properties
2028 if ( pInfo->isCmisDocument( ) )
2030 if ( bMustDelete )
2031 delete pInfo;
2032 return false;
2035 pInfo->ClearCustomProperties();
2036 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2037 for ( const auto& rProperty : aPropertySeq )
2039 if ( !rProperty.Name.isEmpty() )
2040 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
2044 if (pInfo)
2046 rSet->Put(*pInfo);
2047 if ( bMustDelete )
2048 delete pInfo;
2050 return true;
2053 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
2055 m_xPropertiesCtrl->ClearAllLines();
2056 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2057 std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
2058 // tdf#123919 - sort custom document properties
2059 auto const sort = comphelper::string::NaturalStringSorter(
2060 comphelper::getProcessComponentContext(),
2061 Application::GetSettings().GetLanguageTag().getLocale());
2062 std::sort(aCustomProps.begin(), aCustomProps.end(),
2063 [&sort](const std::unique_ptr<CustomProperty>& rLHS,
2064 const std::unique_ptr<CustomProperty>& rRHS) {
2065 return sort.compare(rLHS->m_sName, rRHS->m_sName) < 0;
2067 m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
2070 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2072 DeactivateRC nRet = DeactivateRC::LeavePage;
2073 if ( !m_xPropertiesCtrl->AreAllLinesValid() )
2074 nRet = DeactivateRC::KeepPage;
2075 return nRet;
2078 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2080 return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
2083 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
2084 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2085 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2086 , m_xValueEdit(m_xBuilder->weld_entry("value"))
2088 m_xValueEdit->show();
2089 m_xValueEdit->set_text(aStr);
2092 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
2093 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2094 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2095 , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date")))
2096 , m_xTimeField(m_xBuilder->weld_formatted_spin_button("time"))
2097 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
2099 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
2100 m_xFormatter->EnableEmptyField(false);
2102 m_xDateField->show();
2103 m_xTimeField->show();
2104 m_xDateField->set_date(Date(aDateTime));
2105 m_xFormatter->SetTime(tools::Time(aDateTime));
2108 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
2109 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2110 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2111 , m_xYesButton(m_xBuilder->weld_radio_button("yes"))
2112 , m_xNoButton(m_xBuilder->weld_radio_button("no"))
2114 m_xYesButton->show();
2115 m_xNoButton->show();
2116 if (bValue)
2117 m_xYesButton->set_active(true);
2118 else
2119 m_xNoButton->set_active(true);
2122 // struct CmisPropertyLine ---------------------------------------------
2123 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2124 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2125 , m_sType(CMIS_TYPE_STRING)
2126 , m_bUpdatable(false)
2127 , m_bRequired(false)
2128 , m_bMultiValued(false)
2129 , m_bOpenChoice(false)
2130 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2131 , m_xName(m_xBuilder->weld_label("name"))
2132 , m_xType(m_xBuilder->weld_label("type"))
2134 m_xFrame->set_sensitive(true);
2137 CmisPropertyLine::~CmisPropertyLine( )
2141 // class CmisPropertiesWindow -----------------------------------------
2143 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2144 : m_xBox(std::move(xParent))
2145 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2146 Application::GetSettings().GetLanguageTag().getLanguageType())
2150 CmisPropertiesWindow::~CmisPropertiesWindow()
2154 void CmisPropertiesWindow::ClearAllLines()
2156 m_aCmisPropertiesLines.clear();
2159 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2160 const OUString& sType, const bool bUpdatable,
2161 const bool bRequired, const bool bMultiValued,
2162 const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2164 std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2166 pNewLine->m_sId = sId;
2167 pNewLine->m_sType = sType;
2168 pNewLine->m_bUpdatable = bUpdatable;
2169 pNewLine->m_bRequired = bRequired;
2170 pNewLine->m_bMultiValued = bMultiValued;
2171 pNewLine->m_bOpenChoice = bOpenChoice;
2173 if ( sType == CMIS_TYPE_INTEGER )
2175 Sequence< sal_Int64 > seqValue;
2176 rAny >>= seqValue;
2177 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2178 for ( const auto& rValue : std::as_const(seqValue) )
2180 OUString sValue;
2181 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2182 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2183 pValue->m_xValueEdit->set_editable(bUpdatable);
2184 pNewLine->m_aValues.push_back( std::move(pValue) );
2187 else if ( sType == CMIS_TYPE_DECIMAL )
2189 Sequence< double > seqValue;
2190 rAny >>= seqValue;
2191 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2192 for ( const auto& rValue : std::as_const(seqValue) )
2194 OUString sValue;
2195 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2196 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2197 pValue->m_xValueEdit->set_editable(bUpdatable);
2198 pNewLine->m_aValues.push_back( std::move(pValue) );
2202 else if ( sType == CMIS_TYPE_BOOL )
2204 Sequence<sal_Bool> seqValue;
2205 rAny >>= seqValue;
2206 for ( const auto& rValue : std::as_const(seqValue) )
2208 std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2209 pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2210 pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2211 pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2214 else if ( sType == CMIS_TYPE_STRING )
2216 Sequence< OUString > seqValue;
2217 rAny >>= seqValue;
2218 for ( const auto& rValue : std::as_const(seqValue) )
2220 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2221 pValue->m_xValueEdit->set_editable(bUpdatable);
2222 pNewLine->m_aValues.push_back( std::move(pValue) );
2225 else if ( sType == CMIS_TYPE_DATETIME )
2227 Sequence< util::DateTime > seqValue;
2228 rAny >>= seqValue;
2229 for ( const auto& rValue : std::as_const(seqValue) )
2231 std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2232 pDateTime->m_xDateField->set_sensitive(bUpdatable);
2233 pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2234 pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2237 pNewLine->m_xName->set_label( sName );
2238 pNewLine->m_xName->show();
2239 pNewLine->m_xType->set_label( sType );
2240 pNewLine->m_xType->show();
2242 m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2245 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2247 Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2248 auto aPropertiesSeqRange = asNonConstRange(aPropertiesSeq);
2249 sal_Int32 i = 0;
2250 for ( auto& rxLine : m_aCmisPropertiesLines )
2252 CmisPropertyLine* pLine = rxLine.get();
2254 aPropertiesSeqRange[i].Id = pLine->m_sId;
2255 aPropertiesSeqRange[i].Type = pLine->m_sType;
2256 aPropertiesSeqRange[i].Updatable = pLine->m_bUpdatable;
2257 aPropertiesSeqRange[i].Required = pLine->m_bRequired;
2258 aPropertiesSeqRange[i].OpenChoice = pLine->m_bOpenChoice;
2259 aPropertiesSeqRange[i].MultiValued = pLine->m_bMultiValued;
2261 OUString sPropertyName = pLine->m_xName->get_label();
2262 if ( !sPropertyName.isEmpty() )
2264 aPropertiesSeqRange[i].Name = sPropertyName;
2265 OUString sType = pLine->m_xType->get_label();
2266 if ( CMIS_TYPE_DECIMAL == sType )
2268 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2269 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2270 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2271 auto seqValueRange = asNonConstRange(seqValue);
2272 sal_Int32 k = 0;
2273 for ( const auto& rxValue : pLine->m_aValues )
2275 double dValue = 0.0;
2276 OUString sValue( rxValue->m_xValueEdit->get_text() );
2277 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2278 IsNumberFormat( sValue, nIndex, dValue );
2279 if ( bIsNum )
2280 seqValueRange[k] = dValue;
2281 ++k;
2283 aPropertiesSeqRange[i].Value <<= seqValue;
2285 else if ( CMIS_TYPE_INTEGER == sType )
2287 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2288 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2289 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2290 auto seqValueRange = asNonConstRange(seqValue);
2291 sal_Int32 k = 0;
2292 for ( const auto& rxValue : pLine->m_aValues )
2294 double dValue = 0;
2295 OUString sValue( rxValue->m_xValueEdit->get_text() );
2296 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2297 IsNumberFormat( sValue, nIndex, dValue );
2298 if ( bIsNum )
2299 seqValueRange[k] = static_cast<sal_Int64>(dValue);
2300 ++k;
2302 aPropertiesSeqRange[i].Value <<= seqValue;
2304 else if ( CMIS_TYPE_BOOL == sType )
2306 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2307 sal_Bool* pseqValue = seqValue.getArray();
2308 sal_Int32 k = 0;
2309 for ( const auto& rxYesNo : pLine->m_aYesNos )
2311 bool bValue = rxYesNo->m_xYesButton->get_active();
2312 pseqValue[k] = bValue;
2313 ++k;
2315 aPropertiesSeqRange[i].Value <<= seqValue;
2318 else if ( CMIS_TYPE_DATETIME == sType )
2320 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2321 auto seqValueRange = asNonConstRange(seqValue);
2322 sal_Int32 k = 0;
2323 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2325 Date aTmpDate = rxDateTime->m_xDateField->get_date();
2326 tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2327 util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2328 aTmpTime.GetMin(), aTmpTime.GetHour(),
2329 aTmpDate.GetDay(), aTmpDate.GetMonth(),
2330 aTmpDate.GetYear(), true );
2331 seqValueRange[k] = aDateTime;
2332 ++k;
2334 aPropertiesSeqRange[i].Value <<= seqValue;
2336 else
2338 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2339 auto seqValueRange = asNonConstRange(seqValue);
2340 sal_Int32 k = 0;
2341 for ( const auto& rxValue : pLine->m_aValues )
2343 OUString sValue( rxValue->m_xValueEdit->get_text() );
2344 seqValueRange[k] = sValue;
2345 ++k;
2347 aPropertiesSeqRange[i].Value <<= seqValue;
2350 ++i;
2353 return aPropertiesSeq;
2356 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2357 : m_aPropertiesWin(rBuilder.weld_container("CmisWindow"))
2358 , m_xScrolledWindow(rBuilder.weld_scrolled_window("CmisScroll"))
2360 // set height to something small and force it to take the size
2361 // dictated by the other pages
2362 m_xScrolledWindow->set_size_request(-1, 42);
2365 void CmisPropertiesControl::ClearAllLines()
2367 m_aPropertiesWin.ClearAllLines();
2370 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2371 const OUString& sType, const bool bUpdatable,
2372 const bool bRequired, const bool bMultiValued,
2373 const bool bOpenChoice, Any& aChoices, Any const & rAny
2376 m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2377 bOpenChoice, aChoices, rAny );
2380 // class SfxCmisPropertiesPage -----------------------------------------
2381 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2382 : SfxTabPage(pPage, pController, "sfx/ui/cmisinfopage.ui", "CmisInfoPage", &rItemSet)
2383 , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2387 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2389 m_xPropertiesCtrl.reset();
2392 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2394 const SfxDocumentInfoItem* pItem = nullptr;
2395 SfxDocumentInfoItem* pInfo = nullptr;
2396 bool bMustDelete = false;
2398 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2400 pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2401 if (!pItem)
2402 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2403 else
2405 bMustDelete = true;
2406 pInfo = new SfxDocumentInfoItem( *pItem );
2410 sal_Int32 modifiedNum = 0;
2411 if ( pInfo )
2413 Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2414 Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2416 std::vector< document::CmisProperty > changedProps;
2417 for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2419 if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2421 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2423 Sequence< util::DateTime > oldValue;
2424 aOldProps[i].Value >>= oldValue;
2425 // We only edit hours and minutes
2426 // don't compare NanoSeconds and Seconds
2427 for ( auto& rDateTime : asNonConstRange(oldValue) )
2429 rDateTime.NanoSeconds = 0;
2430 rDateTime.Seconds = 0;
2432 Sequence< util::DateTime > newValue;
2433 aNewProps[i].Value >>= newValue;
2434 if ( oldValue != newValue )
2436 modifiedNum++;
2437 changedProps.push_back( aNewProps[i] );
2440 else if ( aOldProps[i].Value != aNewProps[i].Value )
2442 modifiedNum++;
2443 changedProps.push_back( aNewProps[i] );
2447 Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2448 pInfo->SetCmisProperties( aModifiedProps );
2449 rSet->Put( *pInfo );
2450 if ( bMustDelete )
2451 delete pInfo;
2454 return modifiedNum;
2457 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2459 m_xPropertiesCtrl->ClearAllLines();
2460 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2461 uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2462 for ( auto& rCmisProp : asNonConstRange(aCmisProps) )
2464 m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2465 rCmisProp.Name,
2466 rCmisProp.Type,
2467 rCmisProp.Updatable,
2468 rCmisProp.Required,
2469 rCmisProp.MultiValued,
2470 rCmisProp.OpenChoice,
2471 rCmisProp.Choices,
2472 rCmisProp.Value);
2476 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2478 return DeactivateRC::LeavePage;
2481 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2483 return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2486 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */