sd: keep a non-owning pointer to the OverridingShell
[LibreOffice.git] / sfx2 / source / dialog / dinfdlg.cxx
blob598593e0888c1e0244dc05aa0ee9f1521833b6a5
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/duration.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/urlobj.hxx>
25 #include <utility>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <vcl/weldutils.hxx>
29 #include <unotools/datetime.hxx>
30 #include <unotools/localedatawrapper.hxx>
31 #include <unotools/cmdoptions.hxx>
32 #include <comphelper/processfactory.hxx>
33 #include <comphelper/propertyvalue.hxx>
34 #include <comphelper/stl_types.hxx>
35 #include <comphelper/xmlsechelper.hxx>
36 #include <unotools/useroptions.hxx>
37 #include <svtools/ctrlbox.hxx>
38 #include <svtools/imagemgr.hxx>
39 #include <sal/log.hxx>
40 #include <osl/diagnose.h>
41 #include <osl/file.hxx>
42 #include <comphelper/lok.hxx>
43 #include <LibreOfficeKit/LibreOfficeKitEnums.h>
44 #include <tools/json_writer.hxx>
46 #include <memory>
48 #include <comphelper/sequence.hxx>
49 #include <comphelper/string.hxx>
50 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
51 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
52 #include <unotools/syslocale.hxx>
53 #include <rtl/math.hxx>
54 #include <com/sun/star/beans/PropertyAttribute.hpp>
55 #include <com/sun/star/beans/XPropertyContainer.hpp>
56 #include <com/sun/star/beans/XPropertySet.hpp>
57 #include <com/sun/star/util/DateTime.hpp>
58 #include <com/sun/star/util/Date.hpp>
59 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
60 #include <com/sun/star/util/DateWithTimezone.hpp>
61 #include <com/sun/star/util/Duration.hpp>
62 #include <com/sun/star/document/XDocumentProperties2.hpp>
63 #include <com/sun/star/document/CmisProperty.hpp>
64 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
66 #include <vcl/timer.hxx>
67 #include <vcl/settings.hxx>
68 #include <sfx2/sfxresid.hxx>
69 #include <sfx2/frame.hxx>
70 #include <sfx2/filedlghelper.hxx>
71 #include <sfx2/dinfdlg.hxx>
72 #include <sfx2/sfxsids.hrc>
73 #include <helper.hxx>
74 #include <sfx2/objsh.hxx>
75 #include <sfx2/docfile.hxx>
76 #include <vcl/abstdlg.hxx>
77 #include <sfx2/viewsh.hxx>
79 #include <documentfontsdialog.hxx>
80 #include <dinfdlg.hrc>
81 #include <sfx2/strings.hrc>
82 #include <strings.hxx>
83 #include <comphelper/diagnose_ex.hxx>
84 #include "securitypage.hxx"
86 #include <algorithm>
88 using namespace ::com::sun::star;
89 using namespace ::com::sun::star::uno;
91 struct CustomProperty
93 OUString m_sName;
94 css::uno::Any m_aValue;
96 CustomProperty( OUString sName, css::uno::Any aValue ) :
97 m_sName(std::move( sName )), m_aValue(std::move( aValue )) {}
99 bool operator==(const CustomProperty& rProp) const
101 return m_sName == rProp.m_sName && m_aValue == rProp.m_aValue;
105 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
107 namespace {
109 OUString CreateSizeText( sal_Int64 nSize )
111 OUString aUnitStr = " " + SfxResId(STR_BYTES);
112 sal_Int64 nSize1 = nSize;
113 sal_Int64 nSize2 = nSize1;
114 sal_Int64 nMega = 1024 * 1024;
115 sal_Int64 nGiga = nMega * 1024;
116 double fSize = nSize;
117 int nDec = 0;
119 if ( nSize1 >= 10000 && nSize1 < nMega )
121 nSize1 /= 1024;
122 aUnitStr = " " + SfxResId(STR_KB);
123 fSize /= 1024;
124 nDec = 0;
126 else if ( nSize1 >= nMega && nSize1 < nGiga )
128 nSize1 /= nMega;
129 aUnitStr = " " + SfxResId(STR_MB);
130 fSize /= nMega;
131 nDec = 2;
133 else if ( nSize1 >= nGiga )
135 nSize1 /= nGiga;
136 aUnitStr = " " + SfxResId(STR_GB);
137 fSize /= nGiga;
138 nDec = 3;
140 const SvtSysLocale aSysLocale;
141 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
142 OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
143 if ( nSize1 < nSize2 )
145 aSizeStr = ::rtl::math::doubleToUString( fSize,
146 rtl_math_StringFormat_F, nDec,
147 rLocaleWrapper.getNumDecimalSep()[0] )
148 + aUnitStr
149 + " ("
150 + rLocaleWrapper.getNum( nSize2, 0 )
151 + " "
152 + SfxResId(STR_BYTES)
153 + ")";
155 return aSizeStr;
158 OUString ConvertDateTime_Impl( std::u16string_view rName,
159 const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
161 Date aD(uDT);
162 tools::Time aT(uDT);
163 static constexpr OUString aDelim( u", "_ustr );
164 OUString aStr = rWrapper.getDate( aD )
165 + aDelim
166 + rWrapper.getTime( aT );
167 std::u16string_view aAuthor = comphelper::string::stripStart(rName, ' ');
168 if (!aAuthor.empty())
170 aStr += aDelim + aAuthor;
172 return aStr;
178 SfxDocumentInfoItem::SfxDocumentInfoItem()
179 : m_AutoloadDelay(0)
180 , m_isAutoloadEnabled(false)
181 , m_EditingCycles(0)
182 , m_EditingDuration(0)
183 , m_nFileSize(-1)
184 , m_bHasTemplate( true )
185 , m_bDeleteUserData( false )
186 , m_bUseUserData( true )
187 , m_bUseThumbnailSave( true )
191 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
192 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
193 const uno::Sequence<document::CmisProperty>& i_cmisProps,
194 bool bIs, bool _bIs, sal_Int64 _nFileSize )
195 : SfxStringItem( SID_DOCINFO, rFile, SfxItemType::SfxDocumentInfoItemType )
196 , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
197 , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
198 , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
199 , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
200 , m_TemplateName( i_xDocProps->getTemplateName() )
201 , m_Author( i_xDocProps->getAuthor() )
202 , m_CreationDate( i_xDocProps->getCreationDate() )
203 , m_ModifiedBy( i_xDocProps->getModifiedBy() )
204 , m_ModificationDate( i_xDocProps->getModificationDate() )
205 , m_PrintedBy( i_xDocProps->getPrintedBy() )
206 , m_PrintDate( i_xDocProps->getPrintDate() )
207 , m_EditingCycles( i_xDocProps->getEditingCycles() )
208 , m_EditingDuration( i_xDocProps->getEditingDuration() )
209 , m_Description( i_xDocProps->getDescription() )
210 , m_Keywords( ::comphelper::string::convertCommaSeparated(
211 i_xDocProps->getKeywords()) )
212 , m_Subject( i_xDocProps->getSubject() )
213 , m_Title( i_xDocProps->getTitle() )
214 , m_nFileSize( _nFileSize )
215 , m_bHasTemplate( true )
216 , m_bDeleteUserData( false )
217 , m_bUseUserData( bIs )
218 , m_bUseThumbnailSave( _bIs )
220 Reference< document::XDocumentProperties2 > xDocProps2(i_xDocProps, UNO_QUERY);
221 m_Contributor = ::comphelper::string::convertCommaSeparated(xDocProps2->getContributor());
222 m_Coverage = xDocProps2->getCoverage();
223 m_Identifier = xDocProps2->getIdentifier();
224 m_Publisher = ::comphelper::string::convertCommaSeparated(xDocProps2->getPublisher());
225 m_Relation = ::comphelper::string::convertCommaSeparated(xDocProps2->getRelation());
226 m_Rights = xDocProps2->getRights();
227 m_Source = xDocProps2->getSource();
228 m_Type = xDocProps2->getType();
232 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
233 if ( xContainer.is() )
235 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
236 const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
237 for ( const beans::Property& rProp : lProps )
239 // "fix" property? => not a custom property => ignore it!
240 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
242 SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
243 continue;
246 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
247 AddCustomProperty( rProp.Name, aValue );
251 // get CMIS properties
252 m_aCmisProperties = i_cmisProps;
254 catch ( Exception& ) {}
258 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
259 : SfxStringItem( rItem )
260 , m_AutoloadDelay( rItem.getAutoloadDelay() )
261 , m_AutoloadURL( rItem.getAutoloadURL() )
262 , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
263 , m_DefaultTarget( rItem.getDefaultTarget() )
264 , m_TemplateName( rItem.getTemplateName() )
265 , m_Author( rItem.getAuthor() )
266 , m_CreationDate( rItem.getCreationDate() )
267 , m_ModifiedBy( rItem.getModifiedBy() )
268 , m_ModificationDate( rItem.getModificationDate() )
269 , m_PrintedBy( rItem.getPrintedBy() )
270 , m_PrintDate( rItem.getPrintDate() )
271 , m_EditingCycles( rItem.getEditingCycles() )
272 , m_EditingDuration( rItem.getEditingDuration() )
273 , m_Description( rItem.getDescription() )
274 , m_Keywords( rItem.getKeywords() )
275 , m_Contributor(rItem.getContributor())
276 , m_Coverage(rItem.getCoverage())
277 , m_Identifier(rItem.getIdentifier())
278 , m_Publisher(rItem.getPublisher())
279 , m_Relation(rItem.getRelation())
280 , m_Rights(rItem.getRights())
281 , m_Source(rItem.getSource())
282 , m_Type(rItem.getType())
283 , m_Subject( rItem.getSubject() )
284 , m_Title( rItem.getTitle() )
285 , m_nFileSize ( rItem.m_nFileSize )
286 , m_bHasTemplate( rItem.m_bHasTemplate )
287 , m_bDeleteUserData( rItem.m_bDeleteUserData )
288 , m_bUseUserData( rItem.m_bUseUserData )
289 , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
291 for (auto const & pOtherProp : rItem.m_aCustomProperties)
293 AddCustomProperty( pOtherProp->m_sName, pOtherProp->m_aValue );
296 m_aCmisProperties = rItem.m_aCmisProperties;
299 SfxDocumentInfoItem::~SfxDocumentInfoItem()
301 ClearCustomProperties();
304 SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
306 return new SfxDocumentInfoItem( *this );
309 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
311 if (!SfxStringItem::operator==(rItem))
312 return false;
313 const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
315 return
316 m_AutoloadDelay == rInfoItem.m_AutoloadDelay &&
317 m_AutoloadURL == rInfoItem.m_AutoloadURL &&
318 m_isAutoloadEnabled == rInfoItem.m_isAutoloadEnabled &&
319 m_DefaultTarget == rInfoItem.m_DefaultTarget &&
320 m_Author == rInfoItem.m_Author &&
321 m_CreationDate == rInfoItem.m_CreationDate &&
322 m_ModifiedBy == rInfoItem.m_ModifiedBy &&
323 m_ModificationDate == rInfoItem.m_ModificationDate &&
324 m_PrintedBy == rInfoItem.m_PrintedBy &&
325 m_PrintDate == rInfoItem.m_PrintDate &&
326 m_EditingCycles == rInfoItem.m_EditingCycles &&
327 m_EditingDuration == rInfoItem.m_EditingDuration &&
328 m_Description == rInfoItem.m_Description &&
329 m_Keywords == rInfoItem.m_Keywords &&
330 m_Contributor == rInfoItem.m_Contributor &&
331 m_Coverage == rInfoItem.m_Coverage &&
332 m_Identifier == rInfoItem.m_Identifier &&
333 m_Publisher == rInfoItem.m_Publisher &&
334 m_Relation == rInfoItem.m_Relation &&
335 m_Rights == rInfoItem.m_Rights &&
336 m_Source == rInfoItem.m_Source &&
337 m_Type == rInfoItem.m_Type &&
338 m_Subject == rInfoItem.m_Subject &&
339 m_Title == rInfoItem.m_Title &&
340 comphelper::ContainerUniquePtrEquals(m_aCustomProperties, rInfoItem.m_aCustomProperties) &&
341 m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
345 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
347 m_Author = i_rAuthor;
348 DateTime now( DateTime::SYSTEM );
349 m_CreationDate = now.GetUNODateTime();
350 m_ModifiedBy = OUString();
351 m_PrintedBy = OUString();
352 m_ModificationDate = util::DateTime();
353 m_PrintDate = util::DateTime();
354 m_EditingDuration = 0;
355 m_EditingCycles = 1;
359 void SfxDocumentInfoItem::UpdateDocumentInfo(
360 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
361 bool i_bDoNotUpdateUserDefined) const
363 if (isAutoloadEnabled()) {
364 i_xDocProps->setAutoloadSecs(getAutoloadDelay());
365 i_xDocProps->setAutoloadURL(getAutoloadURL());
366 } else {
367 i_xDocProps->setAutoloadSecs(0);
368 i_xDocProps->setAutoloadURL(OUString());
370 i_xDocProps->setDefaultTarget(getDefaultTarget());
371 i_xDocProps->setAuthor(getAuthor());
372 i_xDocProps->setCreationDate(getCreationDate());
373 i_xDocProps->setModifiedBy(getModifiedBy());
374 i_xDocProps->setModificationDate(getModificationDate());
375 i_xDocProps->setPrintedBy(getPrintedBy());
376 i_xDocProps->setPrintDate(getPrintDate());
377 i_xDocProps->setEditingCycles(getEditingCycles());
378 i_xDocProps->setEditingDuration(getEditingDuration());
379 i_xDocProps->setDescription(getDescription());
380 i_xDocProps->setKeywords(
381 ::comphelper::string::convertCommaSeparated(getKeywords()));
383 Reference<document::XDocumentProperties2> xDocProps2(i_xDocProps, UNO_QUERY);
384 xDocProps2->setContributor(::comphelper::string::convertCommaSeparated(getContributor()));
385 xDocProps2->setCoverage(getCoverage());
386 xDocProps2->setIdentifier(getIdentifier());
387 xDocProps2->setPublisher(::comphelper::string::convertCommaSeparated(getPublisher()));
388 xDocProps2->setRelation(::comphelper::string::convertCommaSeparated(getRelation()));
389 xDocProps2->setRights(getRights());
390 xDocProps2->setSource(getSource());
391 xDocProps2->setType(getType());
392 xDocProps2->setSubject(getSubject());
393 xDocProps2->setTitle(getTitle());
395 // this is necessary in case of replaying a recorded macro:
396 // in this case, the macro may contain the 4 old user-defined DocumentInfo
397 // fields, but not any of the DocumentInfo properties;
398 // as a consequence, most of the UserDefined properties of the
399 // DocumentProperties would be summarily deleted here, which does not
400 // seem like a good idea.
401 if (i_bDoNotUpdateUserDefined)
402 return;
406 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
407 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
408 Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
409 const Sequence< beans::Property > lProps = xSetInfo->getProperties();
410 for ( const beans::Property& rProp : lProps )
412 if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
414 xContainer->removeProperty( rProp.Name );
418 for (auto const & pProp : m_aCustomProperties)
422 xContainer->addProperty( pProp->m_sName,
423 beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
425 catch ( Exception const & )
427 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
431 catch ( Exception const & )
433 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
438 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
440 m_bDeleteUserData = bSet;
444 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
446 m_bUseUserData = bSet;
449 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
451 m_bUseThumbnailSave = bSet;
454 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
456 std::vector< std::unique_ptr<CustomProperty> > aRet;
457 for (auto const & pOtherProp : m_aCustomProperties)
459 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
460 pOtherProp->m_aValue ));
461 aRet.push_back( std::move(pProp) );
464 return aRet;
467 void SfxDocumentInfoItem::ClearCustomProperties()
469 m_aCustomProperties.clear();
472 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
474 std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
475 m_aCustomProperties.push_back( std::move(pProp) );
479 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
481 m_aCmisProperties = cmisProps;
484 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
486 OUString aValue;
487 sal_Int32 nValue = 0;
488 bool bValue = false;
489 bool bIsInt = false;
490 bool bIsString = false;
491 nMemberId &= ~CONVERT_TWIPS;
492 switch ( nMemberId )
494 case MID_DOCINFO_USEUSERDATA:
495 bValue = IsUseUserData();
496 break;
497 case MID_DOCINFO_USETHUMBNAILSAVE:
498 bValue = IsUseThumbnailSave();
499 break;
500 case MID_DOCINFO_DELETEUSERDATA:
501 bValue = m_bDeleteUserData;
502 break;
503 case MID_DOCINFO_AUTOLOADENABLED:
504 bValue = isAutoloadEnabled();
505 break;
506 case MID_DOCINFO_AUTOLOADSECS:
507 bIsInt = true;
508 nValue = getAutoloadDelay();
509 break;
510 case MID_DOCINFO_AUTOLOADURL:
511 bIsString = true;
512 aValue = getAutoloadURL();
513 break;
514 case MID_DOCINFO_DEFAULTTARGET:
515 bIsString = true;
516 aValue = getDefaultTarget();
517 break;
518 case MID_DOCINFO_DESCRIPTION:
519 bIsString = true;
520 aValue = getDescription();
521 break;
522 case MID_DOCINFO_KEYWORDS:
523 bIsString = true;
524 aValue = getKeywords();
525 break;
526 case MID_DOCINFO_SUBJECT:
527 bIsString = true;
528 aValue = getSubject();
529 break;
530 case MID_DOCINFO_TITLE:
531 bIsString = true;
532 aValue = getTitle();
533 break;
534 default:
535 OSL_FAIL("Wrong MemberId!");
536 return false;
539 if ( bIsString )
540 rVal <<= aValue;
541 else if ( bIsInt )
542 rVal <<= nValue;
543 else
544 rVal <<= bValue;
545 return true;
548 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
550 OUString aValue;
551 sal_Int32 nValue=0;
552 bool bValue = false;
553 bool bRet = false;
554 nMemberId &= ~CONVERT_TWIPS;
555 switch ( nMemberId )
557 case MID_DOCINFO_USEUSERDATA:
558 bRet = (rVal >>= bValue);
559 if ( bRet )
560 SetUseUserData( bValue );
561 break;
562 case MID_DOCINFO_USETHUMBNAILSAVE:
563 bRet = (rVal >>=bValue);
564 if ( bRet )
565 SetUseThumbnailSave( bValue );
566 break;
567 case MID_DOCINFO_DELETEUSERDATA:
568 // QUESTION: deleting user data was done here; seems to be superfluous!
569 bRet = (rVal >>= bValue);
570 if ( bRet )
571 SetDeleteUserData( bValue );
572 break;
573 case MID_DOCINFO_AUTOLOADENABLED:
574 bRet = (rVal >>= bValue);
575 if ( bRet )
576 m_isAutoloadEnabled = bValue;
577 break;
578 case MID_DOCINFO_AUTOLOADSECS:
579 bRet = (rVal >>= nValue);
580 if ( bRet )
581 m_AutoloadDelay = nValue;
582 break;
583 case MID_DOCINFO_AUTOLOADURL:
584 bRet = (rVal >>= aValue);
585 if ( bRet )
586 m_AutoloadURL = aValue;
587 break;
588 case MID_DOCINFO_DEFAULTTARGET:
589 bRet = (rVal >>= aValue);
590 if ( bRet )
591 m_DefaultTarget = aValue;
592 break;
593 case MID_DOCINFO_DESCRIPTION:
594 bRet = (rVal >>= aValue);
595 if ( bRet )
596 setDescription(aValue);
597 break;
598 case MID_DOCINFO_KEYWORDS:
599 bRet = (rVal >>= aValue);
600 if ( bRet )
601 setKeywords(aValue);
602 break;
603 case MID_DOCINFO_SUBJECT:
604 bRet = (rVal >>= aValue);
605 if ( bRet )
606 setSubject(aValue);
607 break;
608 case MID_DOCINFO_TITLE:
609 bRet = (rVal >>= aValue);
610 if ( bRet )
611 setTitle(aValue);
612 break;
613 default:
614 OSL_FAIL("Wrong MemberId!");
615 return false;
618 return bRet;
621 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
622 : SfxTabPage(pPage, pController, u"sfx/ui/descriptioninfopage.ui"_ustr, u"DescriptionInfoPage"_ustr, &rItemSet)
623 , m_pInfoItem(nullptr)
624 , m_xTitleEd(m_xBuilder->weld_entry(u"title"_ustr))
625 , m_xThemaEd(m_xBuilder->weld_entry(u"subject"_ustr))
626 , m_xKeywordsEd(m_xBuilder->weld_entry(u"keywords"_ustr))
627 , m_xContributorEd(m_xBuilder->weld_entry(u"contributor"_ustr))
628 , m_xCoverageEd(m_xBuilder->weld_entry(u"coverage"_ustr))
629 , m_xIdentifierEd(m_xBuilder->weld_entry(u"identifier"_ustr))
630 , m_xPublisherEd(m_xBuilder->weld_entry(u"publisher"_ustr))
631 , m_xRelationEd(m_xBuilder->weld_entry(u"relation"_ustr))
632 , m_xRightsEd(m_xBuilder->weld_entry(u"rights"_ustr))
633 , m_xSourceEd(m_xBuilder->weld_entry(u"source"_ustr))
634 , m_xTypeEd(m_xBuilder->weld_entry(u"type"_ustr))
635 , m_xCommentEd(m_xBuilder->weld_text_view(u"comments"_ustr))
637 m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
638 m_xCommentEd->get_height_rows(16));
641 SfxDocumentDescPage::~SfxDocumentDescPage()
645 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
647 return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
650 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
652 // Test whether a change is present
653 const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
654 const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
655 const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
656 const bool bContributorMod = m_xContributorEd->get_value_changed_from_saved();
657 const bool bCoverageMod = m_xCoverageEd->get_value_changed_from_saved();
658 const bool bIdentifierMod = m_xIdentifierEd->get_value_changed_from_saved();
659 const bool bPublisherMod = m_xPublisherEd->get_value_changed_from_saved();
660 const bool bRelationMod = m_xRelationEd->get_value_changed_from_saved();
661 const bool bRightsMod = m_xRightsEd->get_value_changed_from_saved();
662 const bool bSourceMod = m_xSourceEd->get_value_changed_from_saved();
663 const bool bTypeMod = m_xTypeEd->get_value_changed_from_saved();
664 const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
665 if (!(bTitleMod || bThemeMod || bKeywordsMod
666 || bContributorMod || bCoverageMod || bIdentifierMod || bPublisherMod || bRelationMod
667 || bRightsMod || bSourceMod || bTypeMod || bCommentMod))
669 return false;
672 // Generating the output data
673 const SfxDocumentInfoItem* pItem = nullptr;
674 SfxDocumentInfoItem* pInfo = nullptr;
675 const SfxItemSet* pExSet = GetDialogExampleSet();
677 if ( pExSet && !(pItem = pExSet->GetItemIfSet( SID_DOCINFO )) )
678 pInfo = m_pInfoItem;
679 else if ( pItem )
680 pInfo = new SfxDocumentInfoItem( *pItem );
682 if ( !pInfo )
684 SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
685 return false;
688 if ( bTitleMod )
690 pInfo->setTitle( m_xTitleEd->get_text() );
692 if ( bThemeMod )
694 pInfo->setSubject( m_xThemaEd->get_text() );
696 if ( bKeywordsMod )
698 pInfo->setKeywords( m_xKeywordsEd->get_text() );
700 if (bContributorMod)
702 pInfo->setContributor(m_xContributorEd->get_text());
704 if (bCoverageMod)
706 pInfo->setCoverage(m_xCoverageEd->get_text());
708 if (bIdentifierMod)
710 pInfo->setIdentifier(m_xIdentifierEd->get_text());
712 if (bPublisherMod)
714 pInfo->setPublisher(m_xPublisherEd->get_text());
716 if (bRelationMod)
718 pInfo->setRelation(m_xRelationEd->get_text());
720 if (bRightsMod)
722 pInfo->setRights(m_xRightsEd->get_text());
724 if (bSourceMod)
726 pInfo->setSource(m_xSourceEd->get_text());
728 if (bTypeMod)
730 pInfo->setType(m_xTypeEd->get_text());
732 if ( bCommentMod )
734 pInfo->setDescription( m_xCommentEd->get_text() );
736 rSet->Put( *pInfo );
737 // ptr compare OK, pInfo was created above as temporary data holder
738 if ( !areSfxPoolItemPtrsEqual(pInfo, m_pInfoItem) )
740 delete pInfo;
743 return true;
746 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
748 m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
750 m_xTitleEd->set_text(m_pInfoItem->getTitle());
751 m_xThemaEd->set_text(m_pInfoItem->getSubject());
752 m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
753 m_xContributorEd->set_text(m_pInfoItem->getContributor());
754 m_xCoverageEd->set_text(m_pInfoItem->getCoverage());
755 m_xIdentifierEd->set_text(m_pInfoItem->getIdentifier());
756 m_xPublisherEd->set_text(m_pInfoItem->getPublisher());
757 m_xRelationEd->set_text(m_pInfoItem->getRelation());
758 m_xRightsEd->set_text(m_pInfoItem->getRights());
759 m_xSourceEd->set_text(m_pInfoItem->getSource());
760 m_xTypeEd->set_text(m_pInfoItem->getType());
761 m_xCommentEd->set_text(m_pInfoItem->getDescription());
763 m_xTitleEd->save_value();
764 m_xThemaEd->save_value();
765 m_xKeywordsEd->save_value();
766 m_xContributorEd->save_value();
767 m_xCoverageEd->save_value();
768 m_xIdentifierEd->save_value();
769 m_xPublisherEd->save_value();
770 m_xRelationEd->save_value();
771 m_xRightsEd->save_value();
772 m_xSourceEd->save_value();
773 m_xTypeEd->save_value();
774 m_xCommentEd->save_value();
776 const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
777 if (pROItem && pROItem->GetValue())
779 m_xTitleEd->set_editable(false);
780 m_xThemaEd->set_editable(false);
781 m_xKeywordsEd->set_editable(false);
782 m_xContributorEd->set_editable(false);
783 m_xCoverageEd->set_editable(false);
784 m_xIdentifierEd->set_editable(false);
785 m_xPublisherEd->set_editable(false);
786 m_xRelationEd->set_editable(false);
787 m_xRightsEd->set_editable(false);
788 m_xSourceEd->set_editable(false);
789 m_xTypeEd->set_editable(false);
790 m_xCommentEd->set_editable(false);
794 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
795 : SfxTabPage(pPage, pController, u"sfx/ui/documentinfopage.ui"_ustr, u"DocumentInfoPage"_ustr, &rItemSet)
796 , bEnableUseUserData( false )
797 , bHandleDelete( false )
798 , m_xBmp(m_xBuilder->weld_image(u"icon"_ustr))
799 , m_xNameED(m_xBuilder->weld_label(u"nameed"_ustr))
800 , m_xChangePassBtn(m_xBuilder->weld_button(u"changepass"_ustr))
801 , m_xShowTypeFT(m_xBuilder->weld_label(u"showtype"_ustr))
802 , m_xFileValEd(m_xBuilder->weld_link_button(u"showlocation"_ustr))
803 , m_xShowSizeFT(m_xBuilder->weld_label(u"showsize"_ustr))
804 , m_xCreateValFt(m_xBuilder->weld_label(u"showcreate"_ustr))
805 , m_xChangeValFt(m_xBuilder->weld_label(u"showmodify"_ustr))
806 , m_xSignedValFt(m_xBuilder->weld_label(u"showsigned"_ustr))
807 , m_xSignatureBtn(m_xBuilder->weld_button(u"signature"_ustr))
808 , m_xPrintValFt(m_xBuilder->weld_label(u"showprint"_ustr))
809 , m_xTimeLogValFt(m_xBuilder->weld_label(u"showedittime"_ustr))
810 , m_xDocNoValFt(m_xBuilder->weld_label(u"showrevision"_ustr))
811 , m_xUseUserDataCB(m_xBuilder->weld_check_button(u"userdatacb"_ustr))
812 , m_xDeleteBtn(m_xBuilder->weld_button(u"reset"_ustr))
813 , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button(u"thumbnailsavecb"_ustr))
814 , m_xTemplFt(m_xBuilder->weld_label(u"templateft"_ustr))
815 , m_xTemplValFt(m_xBuilder->weld_label(u"showtemplate"_ustr))
816 , m_xImagePreferredDpiCheckButton(m_xBuilder->weld_check_button(u"image-preferred-dpi-checkbutton"_ustr))
817 , m_xImagePreferredDpiComboBox(m_xBuilder->weld_combo_box(u"image-preferred-dpi-combobox"_ustr))
819 m_xUseUserDataCB->set_accessible_description(SfxResId(STR_A11Y_DESC_USERDATA));
821 m_aUnknownSize = m_xShowSizeFT->get_label();
822 m_xShowSizeFT->set_label(OUString());
824 m_aMultiSignedStr = m_xSignedValFt->get_label();
825 m_xSignedValFt->set_label(OUString());
826 m_xImagePreferredDpiComboBox->set_entry_width_chars(5); // "width in chars" in Glade not effective
828 ImplUpdateSignatures();
829 ImplCheckPasswordState();
830 m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
831 m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
832 if (comphelper::LibreOfficeKit::isActive())
833 m_xSignatureBtn->hide();
834 m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
835 m_xImagePreferredDpiCheckButton->connect_toggled(LINK(this, SfxDocumentPage, ImagePreferredDPICheckBoxClicked));
837 // [i96288] Check if the document signature command is enabled
838 // on the main list enable/disable the pushbutton accordingly
839 SvtCommandOptions aCmdOptions;
840 if ( aCmdOptions.LookupDisabled( u"Signature"_ustr ) )
841 m_xSignatureBtn->set_sensitive(false);
844 SfxDocumentPage::~SfxDocumentPage()
846 if (m_xPasswordDialog)
848 m_xPasswordDialog->Response(RET_CANCEL);
849 m_xPasswordDialog.clear();
853 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
855 OUString aName;
856 if (bEnableUseUserData && m_xUseUserDataCB->get_active())
857 aName = SvtUserOptions().GetFullName();
858 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
859 DateTime now( DateTime::SYSTEM );
860 util::DateTime uDT( now.GetUNODateTime() );
861 m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
862 m_xChangeValFt->set_label( u""_ustr );
863 m_xPrintValFt->set_label( u""_ustr );
864 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( tools::Duration() ) );
865 m_xDocNoValFt->set_label(OUString('1'));
866 bHandleDelete = true;
869 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
871 SfxObjectShell* pDoc = SfxObjectShell::Current();
872 if( pDoc )
874 pDoc->SignDocumentContent(GetFrameWeld(), [this] (bool /*bHaveWeSigned*/) {
875 ImplUpdateSignatures();
880 IMPL_LINK_NOARG(SfxDocumentPage, ImagePreferredDPICheckBoxClicked, weld::Toggleable&, void)
882 bool bEnabled = m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE;
883 m_xImagePreferredDpiComboBox->set_sensitive(bEnabled);
886 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
888 SfxObjectShell* pShell = SfxObjectShell::Current();
891 if (!pShell)
892 break;
893 SfxItemSet& rMedSet = pShell->GetMedium()->GetItemSet();
894 std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
895 if (!pFilter)
896 break;
897 if (comphelper::LibreOfficeKit::isActive())
899 // MS Types support max len of 15 characters while OOXML is "unlimited"
900 const sal_uInt16 maxPwdLen = sfx2::IsMSType(pFilter) && !sfx2::IsOOXML(pFilter) ? 15 : 0;
901 // handle the pwd dialog asynchronously
902 VclAbstractDialogFactory * pFact = VclAbstractDialogFactory::Create();
903 m_xPasswordDialog = pFact->CreatePasswordToOpenModifyDialog(GetFrameWeld(), maxPwdLen, false);
904 m_xPasswordDialog->AllowEmpty(); // needed to remove password
905 m_xPasswordDialog->StartExecuteAsync([this, pFilter=std::move(pFilter), &rMedSet, pShell](sal_Int32 nResult)
907 if (nResult == RET_OK)
909 sfx2::SetPassword(pFilter, &rMedSet, m_xPasswordDialog->GetPasswordToOpen(),
910 m_xPasswordDialog->GetPasswordToOpen(), true);
911 tools::JsonWriter payloadJson;
912 payloadJson.put("password", m_xPasswordDialog->GetPasswordToOpen());
913 payloadJson.put("isToModify", false);
915 SfxViewShell *pViewShell = SfxViewShell::Current();
916 if (pViewShell)
917 pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_PASSWORD_RESET, payloadJson.finishAndGetAsOString());
919 pShell->SetModified();
921 m_xPasswordDialog->disposeOnce();
923 } else {
924 sfx2::RequestPassword(pFilter, OUString(), &rMedSet, GetFrameWeld()->GetXWindow());
925 pShell->SetModified();
928 while (false);
931 void SfxDocumentPage::ImplUpdateSignatures()
933 SfxObjectShell* pDoc = SfxObjectShell::Current();
934 if ( !pDoc )
935 return;
937 SfxMedium* pMedium = pDoc->GetMedium();
938 if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
939 return;
941 Reference< security::XDocumentDigitalSignatures > xD;
944 xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
945 xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
947 catch ( const css::uno::DeploymentException& )
950 OUString s;
951 Sequence< security::DocumentSignatureInformation > aInfos;
953 if ( xD.is() )
954 aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
955 uno::Reference< io::XInputStream >() );
956 if ( aInfos.getLength() > 1 )
957 s = m_aMultiSignedStr;
958 else if ( aInfos.getLength() == 1 )
960 const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
961 s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
962 comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
964 m_xSignedValFt->set_label(s);
967 void SfxDocumentPage::ImplCheckPasswordState()
969 SfxObjectShell* pShell = SfxObjectShell::Current();
972 if (!pShell)
973 break;
974 const SfxUnoAnyItem* pEncryptionDataItem = pShell->GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
975 uno::Sequence< beans::NamedValue > aEncryptionData;
976 if (pEncryptionDataItem)
977 pEncryptionDataItem->GetValue() >>= aEncryptionData;
978 else
979 break;
981 if (!aEncryptionData.hasElements())
982 break;
983 m_xChangePassBtn->set_sensitive(true);
984 return;
986 while (false);
987 m_xChangePassBtn->set_sensitive(comphelper::LibreOfficeKit::isActive());
990 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
992 return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
995 void SfxDocumentPage::EnableUseUserData()
997 bEnableUseUserData = true;
998 m_xUseUserDataCB->show();
999 m_xDeleteBtn->show();
1002 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
1004 bool bRet = false;
1006 if ( !bHandleDelete && bEnableUseUserData &&
1007 m_xUseUserDataCB->get_state_changed_from_saved() )
1009 const SfxItemSet* pExpSet = GetDialogExampleSet();
1010 const SfxDocumentInfoItem* pInfoItem;
1012 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO ) ) )
1014 bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1015 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
1016 rSet->Put( *pInfoItem );
1017 bRet = true;
1021 if ( bHandleDelete )
1023 const SfxItemSet* pExpSet = GetDialogExampleSet();
1024 const SfxDocumentInfoItem* pInfoItem;
1025 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
1027 bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
1028 SfxDocumentInfoItem newItem( *pInfoItem );
1029 newItem.resetUserData( bUseAuthor
1030 ? SvtUserOptions().GetFullName()
1031 : OUString() );
1032 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1033 newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1035 newItem.SetDeleteUserData( true );
1036 rSet->Put( newItem );
1037 bRet = true;
1041 if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
1043 const SfxItemSet* pExpSet = GetDialogExampleSet();
1044 const SfxDocumentInfoItem* pInfoItem;
1046 if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
1048 bool bUseThumbnail = ( TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state() );
1049 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave( bUseThumbnail );
1050 rSet->Put( *pInfoItem );
1051 bRet = true;
1055 SfxObjectShell* pDocSh = SfxObjectShell::Current();
1056 if (pDocSh)
1058 uno::Reference<lang::XMultiServiceFactory> xFac(pDocSh->GetModel(), uno::UNO_QUERY);
1059 if (xFac.is())
1061 uno::Reference<beans::XPropertySet> xProps(xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
1062 if (xProps.is())
1064 sal_Int32 nImagePreferredDPI = 0;
1065 if (m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE)
1067 OUString aImagePreferredDPIString = m_xImagePreferredDpiComboBox->get_active_text();
1068 nImagePreferredDPI = aImagePreferredDPIString.toInt32();
1070 xProps->setPropertyValue(u"ImagePreferredDPI"_ustr, uno::Any(nImagePreferredDPI));
1075 return bRet;
1078 void SfxDocumentPage::Reset( const SfxItemSet* rSet )
1080 // Determine the document information
1081 const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
1083 // template data
1084 if (rInfoItem.HasTemplate())
1086 const OUString& rName = rInfoItem.getTemplateName();
1087 if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
1088 m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
1089 else
1090 m_xTemplValFt->set_label(rName);
1092 else
1094 m_xTemplFt->hide();
1095 m_xTemplValFt->hide();
1098 // determine file name
1099 OUString aFile( rInfoItem.GetValue() );
1100 OUString aFactory( aFile );
1101 if ( aFile.getLength() > 2 && aFile[0] == '[' )
1103 sal_Int32 nPos = aFile.indexOf( ']' );
1104 aFactory = aFile.copy( 1, nPos-1 );
1105 aFile = aFile.copy( nPos+1 );
1108 // determine name
1109 INetURLObject aURL(aFile);
1110 OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1111 if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
1112 aName = SfxResId( STR_NONAME );
1113 m_xNameED->set_label( aName );
1115 // determine context symbol
1116 aURL.SetSmartProtocol( INetProtocol::File );
1117 aURL.SetSmartURL( aFactory);
1118 const OUString aMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1119 OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
1120 m_xBmp->set_from_icon_name(aImage);
1122 // determine size and type
1123 OUString aSizeText( m_aUnknownSize );
1124 // we might already know the size as an optional argument passed to .uno:SetDocumentProperties
1125 sal_Int64 nSize = rInfoItem.getFileSize();
1126 // otherwise, for some protocols we can reliably query for it
1127 if (nSize == -1 && (aURL.GetProtocol() == INetProtocol::File || aURL.isAnyKnownWebDAVScheme()))
1128 nSize = SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1129 if (nSize != -1)
1130 aSizeText = CreateSizeText( nSize );
1131 m_xShowSizeFT->set_label( aSizeText );
1133 OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(aMainURL) );
1134 if ( aDescription.isEmpty() )
1135 aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
1136 m_xShowTypeFT->set_label( aDescription );
1138 // determine location
1139 // online we don't know file location so we just set it as the name
1140 if (comphelper::LibreOfficeKit::isActive())
1142 m_xFileValEd->set_label(aName);
1143 m_xFileValEd->set_uri(aName);
1145 // Disable setting/changing password on text files.
1146 // Perhaps this needs to be done for both Online and Desktop.
1147 OUString sExtension(INetURLObject(aMainURL).getExtension());
1148 if (!sExtension.isEmpty())
1150 sExtension = sExtension.toAsciiLowerCase();
1151 if (sExtension == "txt" || sExtension == "csv")
1152 m_xChangePassBtn->set_sensitive(false);
1155 else
1157 aURL.SetSmartURL( aFile);
1158 if ( aURL.GetProtocol() == INetProtocol::File )
1160 INetURLObject aPath(std::move(aURL));
1161 aPath.setFinalSlash();
1162 aPath.removeSegment();
1163 // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
1164 aPath.removeFinalSlash();
1165 OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
1166 m_xFileValEd->set_label(aText);
1167 OUString aURLStr;
1168 osl::FileBase::getFileURLFromSystemPath(aText, aURLStr);
1169 m_xFileValEd->set_uri(aURLStr);
1171 else if (aURL.GetProtocol() != INetProtocol::PrivSoffice)
1173 m_xFileValEd->set_label(aURL.GetPartBeforeLastName());
1174 m_xFileValEd->set_uri(m_xFileValEd->get_label());
1179 // handle access data
1180 bool bUseUserData = rInfoItem.IsUseUserData();
1181 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
1182 m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
1183 rInfoItem.getCreationDate(), rLocaleWrapper ) );
1184 util::DateTime aTime( rInfoItem.getModificationDate() );
1185 if ( aTime.Month > 0 )
1186 m_xChangeValFt->set_label( ConvertDateTime_Impl(
1187 rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
1188 aTime = rInfoItem.getPrintDate();
1189 if ( aTime.Month > 0 )
1190 m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
1191 aTime, rLocaleWrapper ) );
1192 const tools::Long nTime = rInfoItem.getEditingDuration();
1193 if ( bUseUserData )
1195 assert(SAL_MIN_INT32 <= nTime/86400 && nTime/86400 <= SAL_MAX_INT32);
1196 const tools::Duration aD( static_cast<sal_Int32>(nTime)/86400,
1197 (nTime%86400)/3600, (nTime%3600)/60, nTime%60, 0);
1198 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aD ) );
1199 m_xDocNoValFt->set_label( OUString::number(
1200 rInfoItem.getEditingCycles() ) );
1203 bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1205 // Check for cmis properties where otherwise unavailable
1206 if ( rInfoItem.isCmisDocument( ) )
1208 const uno::Sequence< document::CmisProperty >& aCmisProps = rInfoItem.GetCmisProperties();
1209 for ( const auto& rCmisProp : aCmisProps )
1211 if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1212 aSizeText == m_aUnknownSize )
1214 Sequence< sal_Int64 > seqValue;
1215 rCmisProp.Value >>= seqValue;
1216 SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1217 Application::GetSettings().GetLanguageTag().getLanguageType() );
1218 sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1219 if ( seqValue.hasElements() )
1221 OUString sValue = aNumberFormatter.GetInputLineString( seqValue[0], nIndex );
1222 m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1226 util::DateTime uDT;
1227 OUString emptyDate = ConvertDateTime_Impl( u"", uDT, rLocaleWrapper );
1228 if ( rCmisProp.Id == "cmis:creationDate" &&
1229 (m_xCreateValFt->get_label() == emptyDate ||
1230 m_xCreateValFt->get_label().isEmpty()))
1232 Sequence< util::DateTime > seqValue;
1233 rCmisProp.Value >>= seqValue;
1234 if ( seqValue.hasElements() )
1236 m_xCreateValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1239 if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1240 (m_xChangeValFt->get_label() == emptyDate ||
1241 m_xChangeValFt->get_label().isEmpty()))
1243 Sequence< util::DateTime > seqValue;
1244 rCmisProp.Value >>= seqValue;
1245 if ( seqValue.hasElements() )
1247 m_xChangeValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1253 m_xUseUserDataCB->set_active(bUseUserData);
1254 m_xUseUserDataCB->save_state();
1255 m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1256 bHandleDelete = false;
1257 m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1258 m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1259 m_xUseThumbnailSaveCB->save_state();
1261 SfxObjectShell* pDocSh = SfxObjectShell::Current();
1262 sal_Int32 nImagePreferredDPI = 0;
1263 if (pDocSh)
1267 uno::Reference< lang::XMultiServiceFactory > xFac( pDocSh->GetModel(), uno::UNO_QUERY );
1268 if (xFac)
1270 uno::Reference< beans::XPropertySet > xProps( xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY );
1271 if (xProps)
1272 xProps->getPropertyValue(u"ImagePreferredDPI"_ustr) >>= nImagePreferredDPI;
1275 catch( uno::Exception& )
1279 if (nImagePreferredDPI > 0)
1281 m_xImagePreferredDpiCheckButton->set_state(TRISTATE_TRUE);
1282 m_xImagePreferredDpiComboBox->set_sensitive(true);
1283 m_xImagePreferredDpiComboBox->set_entry_text(OUString::number(nImagePreferredDPI));
1285 else
1287 m_xImagePreferredDpiCheckButton->set_state(TRISTATE_FALSE);
1288 m_xImagePreferredDpiComboBox->set_sensitive(false);
1289 m_xImagePreferredDpiComboBox->set_entry_text(u""_ustr);
1294 SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1295 : SfxTabDialogController(pParent, u"sfx/ui/documentpropertiesdialog.ui"_ustr,
1296 u"DocumentPropertiesDialog"_ustr, &rItemSet)
1298 const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1300 #ifdef DBG_UTIL
1301 const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1302 DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1303 #endif
1305 // Determine the Titles
1306 OUString aTitle(m_xDialog->get_title());
1307 const SfxStringItem* pItem = rItemSet.GetItemIfSet( SID_EXPLORER_PROPS_START, false );
1308 if ( !pItem )
1310 // File name
1311 const OUString& aFile( rInfoItem.GetValue() );
1313 INetURLObject aURL;
1314 aURL.SetSmartProtocol( INetProtocol::File );
1315 aURL.SetSmartURL( aFile);
1316 if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1318 OUString aLastName( aURL.GetLastName() );
1319 if ( !aLastName.isEmpty() )
1320 aTitle = aTitle.replaceFirst("%1", aLastName);
1321 else
1322 aTitle = aTitle.replaceFirst("%1", aFile);
1324 else
1325 aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1327 else
1329 aTitle = aTitle.replaceFirst("%1", pItem->GetValue());
1331 m_xDialog->set_title(aTitle);
1333 // Property Pages
1334 AddTabPage(u"general"_ustr, SfxDocumentPage::Create, nullptr);
1335 AddTabPage(u"description"_ustr, SfxDocumentDescPage::Create, nullptr);
1337 AddTabPage(u"customprops"_ustr, SfxCustomPropertiesPage::Create, nullptr);
1339 if (rInfoItem.isCmisDocument())
1340 AddTabPage(u"cmisprops"_ustr, SfxCmisPropertiesPage::Create, nullptr);
1341 else
1342 RemoveTabPage(u"cmisprops"_ustr);
1343 // Disable security page for online as not fully asynced yet
1344 if (!comphelper::LibreOfficeKit::isActive())
1345 AddTabPage(u"security"_ustr, SfxSecurityPage::Create, nullptr);
1346 else
1347 RemoveTabPage(u"security"_ustr);
1350 void SfxDocumentInfoDialog::PageCreated(const OUString& rId, SfxTabPage &rPage)
1352 if (rId == "general")
1353 static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1356 void SfxDocumentInfoDialog::AddFontTabPage()
1358 AddTabPage(u"font"_ustr, SfxResId(STR_FONT_TABPAGE), SfxDocumentFontsPage::Create);
1361 // class CustomPropertiesYesNoButton -------------------------------------
1363 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1364 std::unique_ptr<weld::RadioButton> xYesButton,
1365 std::unique_ptr<weld::RadioButton> xNoButton)
1366 : m_xTopLevel(std::move(xTopLevel))
1367 , m_xYesButton(std::move(xYesButton))
1368 , m_xNoButton(std::move(xNoButton))
1370 CheckNo();
1373 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1378 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1379 : GenericDialogController(pParent, u"sfx/ui/editdurationdialog.ui"_ustr, u"EditDurationDialog"_ustr)
1380 , m_xNegativeCB(m_xBuilder->weld_check_button(u"negative"_ustr))
1381 , m_xYearNF(m_xBuilder->weld_spin_button(u"years"_ustr))
1382 , m_xMonthNF(m_xBuilder->weld_spin_button(u"months"_ustr))
1383 , m_xDayNF(m_xBuilder->weld_spin_button(u"days"_ustr))
1384 , m_xHourNF(m_xBuilder->weld_spin_button(u"hours"_ustr))
1385 , m_xMinuteNF(m_xBuilder->weld_spin_button(u"minutes"_ustr))
1386 , m_xSecondNF(m_xBuilder->weld_spin_button(u"seconds"_ustr))
1387 , m_xMSecondNF(m_xBuilder->weld_spin_button(u"milliseconds"_ustr))
1389 m_xNegativeCB->set_active(rDuration.Negative);
1390 m_xYearNF->set_value(rDuration.Years);
1391 m_xMonthNF->set_value(rDuration.Months);
1392 m_xDayNF->set_value(rDuration.Days);
1393 m_xHourNF->set_value(rDuration.Hours);
1394 m_xMinuteNF->set_value(rDuration.Minutes);
1395 m_xSecondNF->set_value(rDuration.Seconds);
1396 m_xMSecondNF->set_value(rDuration.NanoSeconds);
1399 util::Duration DurationDialog_Impl::GetDuration() const
1401 util::Duration aRet;
1402 aRet.Negative = m_xNegativeCB->get_active();
1403 aRet.Years = m_xYearNF->get_value();
1404 aRet.Months = m_xMonthNF->get_value();
1405 aRet.Days = m_xDayNF->get_value();
1406 aRet.Hours = m_xHourNF->get_value();
1407 aRet.Minutes = m_xMinuteNF->get_value();
1408 aRet.Seconds = m_xSecondNF->get_value();
1409 aRet.NanoSeconds = m_xMSecondNF->get_value();
1410 return aRet;
1413 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1414 std::unique_ptr<weld::Button> xEditButton)
1415 : m_xEntry(std::move(xEntry))
1416 , m_xEditButton(std::move(xEditButton))
1418 m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1419 SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1422 void CustomPropertiesDurationField::set_visible(bool bVisible)
1424 m_xEntry->set_visible(bVisible);
1425 m_xEditButton->set_visible(bVisible);
1428 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1430 m_aDuration = rDuration;
1431 OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1432 SfxResId(SFX_ST_DURATION_FORMAT);
1433 sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1434 sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1435 sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days ) );
1436 sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours ) );
1437 sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1438 sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1439 m_xEntry->set_text(sText);
1442 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1444 m_xDurationDialog = std::make_shared<DurationDialog_Impl>(&rButton, GetDuration());
1445 weld::DialogController::runAsync(m_xDurationDialog, [&](sal_Int32 response)
1447 if (response == RET_OK)
1449 SetDuration(m_xDurationDialog->GetDuration());
1454 CustomPropertiesDurationField::~CustomPropertiesDurationField()
1456 if (m_xDurationDialog)
1457 m_xDurationDialog->response(RET_CANCEL);
1460 namespace
1462 void fillNameBox(weld::ComboBox& rNameBox)
1464 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1465 rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1466 Size aSize(rNameBox.get_preferred_size());
1467 rNameBox.set_size_request(aSize.Width(), aSize.Height());
1470 void fillTypeBox(weld::ComboBox& rTypeBox)
1472 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1474 OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1475 rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1477 rTypeBox.set_active(0);
1478 Size aSize(rTypeBox.get_preferred_size());
1479 rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1483 // struct CustomPropertyLine ---------------------------------------------
1484 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1485 : m_pParent(pParent)
1486 , m_xBuilder(Application::CreateBuilder(pContainer, u"sfx/ui/linefragment.ui"_ustr))
1487 , m_xLine(m_xBuilder->weld_container(u"lineentry"_ustr))
1488 , m_xNameBox(m_xBuilder->weld_combo_box(u"namebox"_ustr))
1489 , m_xTypeBox(m_xBuilder->weld_combo_box(u"typebox"_ustr))
1490 , m_xValueEdit(m_xBuilder->weld_entry(u"valueedit"_ustr))
1491 , m_xDateTimeBox(m_xBuilder->weld_widget(u"datetimebox"_ustr))
1492 , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr))))
1493 , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr)))
1494 , m_xDurationBox(m_xBuilder->weld_widget(u"durationbox"_ustr))
1495 , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry(u"duration"_ustr),
1496 m_xBuilder->weld_button(u"durationbutton"_ustr)))
1497 , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget(u"yesno"_ustr),
1498 m_xBuilder->weld_radio_button(u"yes"_ustr),
1499 m_xBuilder->weld_radio_button(u"no"_ustr)))
1500 , m_xRemoveButton(m_xBuilder->weld_button(u"remove"_ustr))
1501 , m_bTypeLostFocus( false )
1503 fillNameBox(*m_xNameBox);
1504 fillTypeBox(*m_xTypeBox);
1506 m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1507 m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1508 m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1509 //add lose focus handlers of date/time fields
1510 m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1513 void CustomPropertyLine::Clear()
1515 m_xNameBox->set_active(-1);
1516 m_xValueEdit->set_text(OUString());
1520 void CustomPropertyLine::Hide()
1522 m_xLine->hide();
1525 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1526 weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1527 : m_nHeight(0)
1528 , m_nLineHeight(0)
1529 , m_nScrollPos(0)
1530 , m_pCurrentLine(nullptr)
1531 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1532 Application::GetSettings().GetLanguageTag().getLanguageType())
1533 , m_aEditLoseFocusIdle("sfx2 CustomPropertiesWindow loseFocusIdle")
1534 , m_aBoxLoseFocusIdle("sfx2 CustomPropertiesWindow m_aBoxLoseFocusIdle")
1535 , m_rBody(rParent)
1536 , m_rHeaderAccName(rHeaderAccName)
1537 , m_rHeaderAccType(rHeaderAccType)
1538 , m_rHeaderAccValue(rHeaderAccValue)
1540 m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1541 m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1542 m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1543 m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1546 CustomPropertiesWindow::~CustomPropertiesWindow()
1548 m_aEditLoseFocusIdle.Stop();
1549 m_aBoxLoseFocusIdle.Stop();
1551 m_pCurrentLine = nullptr;
1554 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1556 auto nType = rBox.get_active_id().toInt32();
1557 m_xValueEdit->set_visible( (Custom_Type_Text == nType) || (Custom_Type_Number == nType) );
1558 m_xDateTimeBox->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1559 m_xDateField->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1560 m_xTimeField->set_visible( Custom_Type_Datetime == nType );
1561 m_xDurationBox->set_visible( Custom_Type_Duration == nType );
1562 m_xDurationField->set_visible( Custom_Type_Duration == nType );
1563 m_xYesNoButton->set_visible( Custom_Type_Boolean == nType );
1566 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1568 DoTypeHdl(rBox);
1571 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1573 StoreCustomProperties();
1575 auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1576 [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1577 if ( pFound != m_aCustomPropertiesLines.end() )
1579 sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1580 sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1581 m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1583 ReloadLinesContent();
1586 m_aRemovedHdl.Call(nullptr);
1589 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1591 m_pParent->Remove(this);
1594 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1596 m_pCurrentLine = pLine;
1597 m_aEditLoseFocusIdle.Start();
1600 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1602 if (!m_bTypeLostFocus)
1603 m_pParent->EditLoseFocus(this);
1604 else
1605 m_bTypeLostFocus = false;
1608 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1610 m_pCurrentLine = pLine;
1611 m_aBoxLoseFocusIdle.Start();
1614 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1616 m_pParent->BoxLoseFocus(this);
1619 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1621 ValidateLine( m_pCurrentLine, false );
1624 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1626 ValidateLine( m_pCurrentLine, true );
1629 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1631 bool bIsValid = true;
1632 pLine->m_bTypeLostFocus = false;
1633 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1634 OUString sValue = pLine->m_xValueEdit->get_text();
1635 if ( sValue.isEmpty() )
1636 return true;
1638 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1639 if ( Custom_Type_Number == nType )
1640 // tdf#116214 Scientific format allows to use also standard numbers
1641 nIndex = const_cast< SvNumberFormatter& >(
1642 m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1643 else if ( Custom_Type_Date == nType )
1644 nIndex = const_cast< SvNumberFormatter& >(
1645 m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1647 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1649 sal_uInt32 nTemp = nIndex;
1650 double fDummy = 0.0;
1651 bIsValid = const_cast< SvNumberFormatter& >(
1652 m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1653 if ( bIsValid && nTemp != nIndex )
1654 // sValue is a number but the format doesn't match the index
1655 bIsValid = false;
1658 return bIsValid;
1661 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1663 if (pLine && !IsLineValid(pLine))
1665 if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1666 pLine->m_bTypeLostFocus = true;
1667 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1668 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1669 if (xMessageBox->run() == RET_OK)
1670 pLine->m_xTypeBox->set_active_id(OUString::number(Custom_Type_Text));
1671 else
1672 pLine->m_xValueEdit->grab_focus();
1676 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1678 while (GetExistingLineCount() < nCount)
1680 CreateNewLine();
1684 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1686 m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1687 ReloadLinesContent();
1690 void CustomPropertiesWindow::CreateNewLine()
1692 CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1693 pNewLine->m_xNameBox->set_accessible_relation_labeled_by(&m_rHeaderAccName);
1694 pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1695 pNewLine->m_xTypeBox->set_accessible_relation_labeled_by(&m_rHeaderAccType);
1696 pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1697 pNewLine->m_xValueEdit->set_accessible_relation_labeled_by(&m_rHeaderAccValue);
1698 pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1700 m_aCustomPropertiesLines.emplace_back( pNewLine );
1702 // this breaks online's jsdialogbuilder
1703 if (!comphelper::LibreOfficeKit::isActive()){
1704 // for ui-testing. Distinguish the elements in the lines
1705 sal_uInt16 nSize = m_aCustomPropertiesLines.size();
1706 pNewLine->m_xNameBox->set_buildable_name(
1707 pNewLine->m_xNameBox->get_buildable_name() + OUString::number(nSize));
1708 pNewLine->m_xTypeBox->set_buildable_name(
1709 pNewLine->m_xTypeBox->get_buildable_name() + OUString::number(nSize));
1710 pNewLine->m_xValueEdit->set_buildable_name(
1711 pNewLine->m_xValueEdit->get_buildable_name() + OUString::number(nSize));
1712 pNewLine->m_xRemoveButton->set_buildable_name(
1713 pNewLine->m_xRemoveButton->get_buildable_name() + OUString::number(nSize));
1716 pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1719 bool CustomPropertiesWindow::AreAllLinesValid() const
1721 bool bRet = true;
1722 for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1724 if ( !IsLineValid( pLine.get() ) )
1726 bRet = false;
1727 break;
1731 return bRet;
1734 void CustomPropertiesWindow::ClearAllLines()
1736 for (auto& pLine : m_aCustomPropertiesLines)
1738 pLine->Clear();
1740 m_pCurrentLine = nullptr;
1741 m_aCustomProperties.clear();
1742 m_nScrollPos = 0;
1745 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1747 StoreCustomProperties();
1748 m_nScrollPos += nNewPos;
1749 ReloadLinesContent();
1752 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1754 StoreCustomProperties();
1756 Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1757 std::transform(
1758 m_aCustomProperties.begin(), m_aCustomProperties.end(), aPropertiesSeq.getArray(),
1759 [](const auto& el) { return comphelper::makePropertyValue(el->m_sName, el->m_aValue); });
1761 return aPropertiesSeq;
1764 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1765 : m_xTimeField(std::move(xTimeField))
1766 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1767 , m_isUTC(false)
1769 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1770 m_xFormatter->EnableEmptyField(false);
1773 tools::Time CustomPropertiesTimeField::get_value() const
1775 return m_xFormatter->GetTime();
1778 void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1780 m_xFormatter->SetTime(rTime);
1783 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1787 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1788 : m_xDateField(pDateField)
1790 DateTime aDateTime(DateTime::SYSTEM);
1791 m_xDateField->set_date(aDateTime);
1794 void CustomPropertiesDateField::set_visible(bool bVisible)
1796 m_xDateField->set_visible(bVisible);
1799 Date CustomPropertiesDateField::get_date() const
1801 return m_xDateField->get_date();
1804 void CustomPropertiesDateField::set_date(const Date& rDate)
1806 m_xDateField->set_date(rDate);
1809 CustomPropertiesDateField::~CustomPropertiesDateField()
1813 void CustomPropertiesWindow::StoreCustomProperties()
1815 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1817 for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1819 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1821 OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1822 if (!sPropertyName.isEmpty())
1824 m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1825 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1826 if (Custom_Type_Number == nType)
1828 double nValue = 0;
1829 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1830 bool bIsNum = m_aNumberFormatter.
1831 IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1832 if (bIsNum)
1833 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1835 else if (Custom_Type_Boolean == nType)
1837 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1838 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1840 else if (Custom_Type_Datetime == nType)
1842 Date aTmpDate = pLine->m_xDateField->get_date();
1843 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1844 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1845 aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1846 aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1847 pLine->m_xTimeField->m_isUTC);
1848 if (pLine->m_xDateField->m_TZ)
1850 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1851 aDateTime, *pLine->m_xDateField->m_TZ);
1853 else
1855 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1858 else if (Custom_Type_Date == nType)
1860 Date aTmpDate = pLine->m_xDateField->get_date();
1861 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1862 aTmpDate.GetYear());
1863 if (pLine->m_xDateField->m_TZ)
1865 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1866 aDate, *pLine->m_xDateField->m_TZ);
1868 else
1870 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1873 else if (Custom_Type_Duration == nType)
1875 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1877 else
1879 OUString sValue(pLine->m_xValueEdit->get_text());
1880 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1886 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1888 m_aCustomProperties = std::move(rProperties);
1889 ReloadLinesContent();
1892 void CustomPropertiesWindow::ReloadLinesContent()
1894 double nTmpValue = 0;
1895 bool bTmpValue = false;
1896 OUString sTmpValue;
1897 util::DateTime aTmpDateTime;
1898 util::Date aTmpDate;
1899 util::DateTimeWithTimezone aTmpDateTimeTZ;
1900 util::DateWithTimezone aTmpDateTZ;
1901 util::Duration aTmpDuration;
1902 SvtSysLocale aSysLocale;
1903 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1904 CustomProperties nType = Custom_Type_Unknown;
1905 OUString sValue;
1907 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1908 sal_uInt32 i = 0;
1910 for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1912 const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1913 const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1915 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1916 pLine->Clear();
1918 pLine->m_xNameBox->set_entry_text(rName);
1919 pLine->m_xLine->show();
1921 if (!rAny.hasValue())
1923 pLine->m_xValueEdit->set_text(OUString());
1925 else if (rAny >>= nTmpValue)
1927 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1928 sValue = m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex);
1929 pLine->m_xValueEdit->set_text(sValue);
1930 nType = Custom_Type_Number;
1932 else if (rAny >>= bTmpValue)
1934 sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1935 nType = Custom_Type_Boolean;
1937 else if (rAny >>= sTmpValue)
1939 pLine->m_xValueEdit->set_text(sTmpValue);
1940 nType = Custom_Type_Text;
1942 else if (rAny >>= aTmpDate)
1944 pLine->m_xDateField->set_date(Date(aTmpDate));
1945 nType = Custom_Type_Date;
1947 else if (rAny >>= aTmpDateTime)
1949 pLine->m_xDateField->set_date(Date(aTmpDateTime));
1950 pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1951 pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1952 nType = Custom_Type_Datetime;
1954 else if (rAny >>= aTmpDateTZ)
1956 pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1957 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1958 pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1959 nType = Custom_Type_Date;
1962 else if (rAny >>= aTmpDateTimeTZ)
1964 util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1965 pLine->m_xDateField->set_date(Date(rDT));
1966 pLine->m_xTimeField->set_value(tools::Time(rDT));
1967 pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1968 pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1969 nType = Custom_Type_Datetime;
1971 else if (rAny >>= aTmpDuration)
1973 nType = Custom_Type_Duration;
1974 pLine->m_xDurationField->SetDuration(aTmpDuration);
1977 if (Custom_Type_Boolean == nType)
1979 if (bTmpValue)
1980 pLine->m_xYesNoButton->CheckYes();
1981 else
1982 pLine->m_xYesNoButton->CheckNo();
1984 pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1986 pLine->DoTypeHdl(*pLine->m_xTypeBox);
1989 // tdf#132667 - grab focus on the last inserted property
1990 if (i > 0 && m_aCustomProperties[nDataModelPos + i - 1]->m_sName.isEmpty())
1992 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i - 1].get();
1993 pLine->m_xNameBox->grab_focus();
1996 while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1998 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1999 pLine->Hide();
2000 i++;
2004 CustomPropertiesControl::CustomPropertiesControl()
2005 : m_nThumbPos(0)
2009 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
2011 m_xBox = rBuilder.weld_widget(u"box"_ustr);
2012 m_xBody = rBuilder.weld_container(u"properties"_ustr);
2014 m_xName = rBuilder.weld_label(u"name"_ustr);
2015 m_xType = rBuilder.weld_label(u"type"_ustr);
2016 m_xValue = rBuilder.weld_label(u"value"_ustr);
2017 m_xVertScroll = rBuilder.weld_scrolled_window(u"scroll"_ustr, true);
2018 m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
2020 m_xBox->set_stack_background();
2021 m_xVertScroll->show();
2023 std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
2024 Size aLineSize(xNewLine->m_xLine->get_preferred_size());
2025 m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
2026 m_xBody->set_size_request(aLineSize.Width() + 6, -1);
2027 auto nHeight = aLineSize.Height() * 8;
2028 m_xVertScroll->set_size_request(-1, nHeight + 6);
2030 m_xPropertiesWin->SetHeight(nHeight);
2031 m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
2033 m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
2034 m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
2035 m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
2037 m_xBody->move(xNewLine->m_xLine.get(), nullptr);
2038 xNewLine.reset();
2040 m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
2042 m_xVertScroll->vadjustment_set_lower(0);
2043 m_xVertScroll->vadjustment_set_upper(0);
2044 m_xVertScroll->vadjustment_set_page_size(0xFFFF);
2046 Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
2047 m_xVertScroll->connect_vadjustment_changed(aScrollLink);
2049 ResizeHdl(Size(-1, nHeight));
2052 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
2054 int nHeight = rSize.Height() - 6;
2055 if (nHeight == m_xPropertiesWin->GetHeight())
2056 return;
2057 m_xPropertiesWin->SetHeight(nHeight);
2058 sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
2059 sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
2060 m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
2061 m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
2062 m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
2063 m_xPropertiesWin->ReloadLinesContent();
2066 CustomPropertiesControl::~CustomPropertiesControl()
2070 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
2072 sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
2073 int nThumbPos = rScrollBar.vadjustment_get_value();
2074 nOffset *= ( m_nThumbPos - nThumbPos );
2075 m_nThumbPos = nThumbPos;
2076 m_xPropertiesWin->DoScroll( nOffset );
2079 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
2081 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2082 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2083 if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
2085 m_xVertScroll->vadjustment_set_value(nLineCount - 1);
2086 ScrollHdl(*m_xVertScroll);
2090 void CustomPropertiesControl::AddLine( Any const & rAny )
2092 m_xPropertiesWin->AddLine( OUString(), rAny );
2093 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2094 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2095 if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
2097 m_xVertScroll->vadjustment_set_value(nLineCount + 1);
2098 ScrollHdl(*m_xVertScroll);
2102 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
2104 m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
2105 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2106 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2109 // class SfxCustomPropertiesPage -----------------------------------------
2110 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
2111 : SfxTabPage(pPage, pController, u"sfx/ui/custominfopage.ui"_ustr, u"CustomInfoPage"_ustr, &rItemSet)
2112 , m_xPropertiesCtrl(new CustomPropertiesControl)
2113 , m_xAdd(m_xBuilder->weld_button(u"add"_ustr))
2115 m_xPropertiesCtrl->Init(*m_xBuilder);
2116 m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
2119 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
2121 m_xPropertiesCtrl.reset();
2124 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
2126 // tdf#115853: reload current lines before adding a brand new one
2127 // indeed the info are deleted by ClearCustomProperties
2128 // each time SfxDocumentInfoItem destructor is called
2129 SfxDocumentInfoItem pInfo;
2130 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2131 for ( const auto& rProperty : aPropertySeq )
2133 if ( !rProperty.Name.isEmpty() )
2135 pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
2139 Any aAny;
2140 m_xPropertiesCtrl->AddLine(aAny);
2143 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
2145 const SfxDocumentInfoItem* pItem = nullptr;
2146 SfxDocumentInfoItem* pInfo = nullptr;
2147 bool bMustDelete = false;
2149 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2151 pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2152 if (!pItem)
2153 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2154 else
2156 bMustDelete = true;
2157 pInfo = new SfxDocumentInfoItem( *pItem );
2161 if ( pInfo )
2163 // If it's a CMIS document, we can't save custom properties
2164 if ( pInfo->isCmisDocument( ) )
2166 if ( bMustDelete )
2167 delete pInfo;
2168 return false;
2171 pInfo->ClearCustomProperties();
2172 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2173 for ( const auto& rProperty : aPropertySeq )
2175 if ( !rProperty.Name.isEmpty() )
2176 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
2180 if (pInfo)
2182 rSet->Put(*pInfo);
2183 if ( bMustDelete )
2184 delete pInfo;
2186 return true;
2189 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
2191 m_xPropertiesCtrl->ClearAllLines();
2192 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2193 std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
2194 // tdf#123919 - sort custom document properties
2195 auto const sort = comphelper::string::NaturalStringSorter(
2196 comphelper::getProcessComponentContext(),
2197 Application::GetSettings().GetLanguageTag().getLocale());
2198 std::sort(aCustomProps.begin(), aCustomProps.end(),
2199 [&sort](const std::unique_ptr<CustomProperty>& rLHS,
2200 const std::unique_ptr<CustomProperty>& rRHS) {
2201 return sort.compare(rLHS->m_sName, rRHS->m_sName) < 0;
2203 m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
2206 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2208 DeactivateRC nRet = DeactivateRC::LeavePage;
2209 if ( !m_xPropertiesCtrl->AreAllLinesValid() )
2210 nRet = DeactivateRC::KeepPage;
2211 return nRet;
2214 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2216 return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
2219 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
2220 : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2221 , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2222 , m_xValueEdit(m_xBuilder->weld_entry(u"value"_ustr))
2224 m_xValueEdit->show();
2225 m_xValueEdit->set_text(aStr);
2228 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
2229 : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2230 , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2231 , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr)))
2232 , m_xTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr))
2233 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
2235 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
2236 m_xFormatter->EnableEmptyField(false);
2238 m_xDateField->show();
2239 m_xTimeField->show();
2240 m_xDateField->set_date(Date(aDateTime));
2241 m_xFormatter->SetTime(tools::Time(aDateTime));
2244 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
2245 : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2246 , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2247 , m_xYesButton(m_xBuilder->weld_radio_button(u"yes"_ustr))
2248 , m_xNoButton(m_xBuilder->weld_radio_button(u"no"_ustr))
2250 m_xYesButton->show();
2251 m_xNoButton->show();
2252 if (bValue)
2253 m_xYesButton->set_active(true);
2254 else
2255 m_xNoButton->set_active(true);
2258 // struct CmisPropertyLine ---------------------------------------------
2259 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2260 : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2261 , m_sType(CMIS_TYPE_STRING)
2262 , m_bUpdatable(false)
2263 , m_bRequired(false)
2264 , m_bMultiValued(false)
2265 , m_bOpenChoice(false)
2266 , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2267 , m_xName(m_xBuilder->weld_label(u"name"_ustr))
2268 , m_xType(m_xBuilder->weld_label(u"type"_ustr))
2270 m_xFrame->set_sensitive(true);
2273 CmisPropertyLine::~CmisPropertyLine( )
2277 // class CmisPropertiesWindow -----------------------------------------
2279 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2280 : m_xBox(std::move(xParent))
2281 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2282 Application::GetSettings().GetLanguageTag().getLanguageType())
2286 CmisPropertiesWindow::~CmisPropertiesWindow()
2290 void CmisPropertiesWindow::ClearAllLines()
2292 m_aCmisPropertiesLines.clear();
2295 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2296 const OUString& sType, const bool bUpdatable,
2297 const bool bRequired, const bool bMultiValued,
2298 const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2300 std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2302 pNewLine->m_sId = sId;
2303 pNewLine->m_sType = sType;
2304 pNewLine->m_bUpdatable = bUpdatable;
2305 pNewLine->m_bRequired = bRequired;
2306 pNewLine->m_bMultiValued = bMultiValued;
2307 pNewLine->m_bOpenChoice = bOpenChoice;
2309 if ( sType == CMIS_TYPE_INTEGER )
2311 Sequence< sal_Int64 > seqValue;
2312 rAny >>= seqValue;
2313 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2314 for (const auto& rValue : seqValue)
2316 OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2317 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2318 pValue->m_xValueEdit->set_editable(bUpdatable);
2319 pNewLine->m_aValues.push_back( std::move(pValue) );
2322 else if ( sType == CMIS_TYPE_DECIMAL )
2324 Sequence< double > seqValue;
2325 rAny >>= seqValue;
2326 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2327 for (const auto& rValue : seqValue)
2329 OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2330 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2331 pValue->m_xValueEdit->set_editable(bUpdatable);
2332 pNewLine->m_aValues.push_back( std::move(pValue) );
2336 else if ( sType == CMIS_TYPE_BOOL )
2338 Sequence<sal_Bool> seqValue;
2339 rAny >>= seqValue;
2340 for (const auto& rValue : seqValue)
2342 std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2343 pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2344 pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2345 pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2348 else if ( sType == CMIS_TYPE_STRING )
2350 Sequence< OUString > seqValue;
2351 rAny >>= seqValue;
2352 for (const auto& rValue : seqValue)
2354 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2355 pValue->m_xValueEdit->set_editable(bUpdatable);
2356 pNewLine->m_aValues.push_back( std::move(pValue) );
2359 else if ( sType == CMIS_TYPE_DATETIME )
2361 Sequence< util::DateTime > seqValue;
2362 rAny >>= seqValue;
2363 for (const auto& rValue : seqValue)
2365 std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2366 pDateTime->m_xDateField->set_sensitive(bUpdatable);
2367 pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2368 pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2371 pNewLine->m_xName->set_label( sName );
2372 pNewLine->m_xName->show();
2373 pNewLine->m_xType->set_label( sType );
2374 pNewLine->m_xType->show();
2376 m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2379 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2381 Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2382 auto aPropertiesSeqRange = asNonConstRange(aPropertiesSeq);
2383 sal_Int32 i = 0;
2384 for ( auto& rxLine : m_aCmisPropertiesLines )
2386 CmisPropertyLine* pLine = rxLine.get();
2388 aPropertiesSeqRange[i].Id = pLine->m_sId;
2389 aPropertiesSeqRange[i].Type = pLine->m_sType;
2390 aPropertiesSeqRange[i].Updatable = pLine->m_bUpdatable;
2391 aPropertiesSeqRange[i].Required = pLine->m_bRequired;
2392 aPropertiesSeqRange[i].OpenChoice = pLine->m_bOpenChoice;
2393 aPropertiesSeqRange[i].MultiValued = pLine->m_bMultiValued;
2395 OUString sPropertyName = pLine->m_xName->get_label();
2396 if ( !sPropertyName.isEmpty() )
2398 aPropertiesSeqRange[i].Name = sPropertyName;
2399 OUString sType = pLine->m_xType->get_label();
2400 if ( CMIS_TYPE_DECIMAL == sType )
2402 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2403 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2404 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2405 auto seqValueRange = asNonConstRange(seqValue);
2406 sal_Int32 k = 0;
2407 for ( const auto& rxValue : pLine->m_aValues )
2409 double dValue = 0.0;
2410 OUString sValue( rxValue->m_xValueEdit->get_text() );
2411 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2412 IsNumberFormat( sValue, nIndex, dValue );
2413 if ( bIsNum )
2414 seqValueRange[k] = dValue;
2415 ++k;
2417 aPropertiesSeqRange[i].Value <<= seqValue;
2419 else if ( CMIS_TYPE_INTEGER == sType )
2421 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2422 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2423 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2424 auto seqValueRange = asNonConstRange(seqValue);
2425 sal_Int32 k = 0;
2426 for ( const auto& rxValue : pLine->m_aValues )
2428 double dValue = 0;
2429 OUString sValue( rxValue->m_xValueEdit->get_text() );
2430 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2431 IsNumberFormat( sValue, nIndex, dValue );
2432 if ( bIsNum )
2433 seqValueRange[k] = static_cast<sal_Int64>(dValue);
2434 ++k;
2436 aPropertiesSeqRange[i].Value <<= seqValue;
2438 else if ( CMIS_TYPE_BOOL == sType )
2440 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2441 sal_Bool* pseqValue = seqValue.getArray();
2442 sal_Int32 k = 0;
2443 for ( const auto& rxYesNo : pLine->m_aYesNos )
2445 bool bValue = rxYesNo->m_xYesButton->get_active();
2446 pseqValue[k] = bValue;
2447 ++k;
2449 aPropertiesSeqRange[i].Value <<= seqValue;
2452 else if ( CMIS_TYPE_DATETIME == sType )
2454 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2455 auto seqValueRange = asNonConstRange(seqValue);
2456 sal_Int32 k = 0;
2457 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2459 Date aTmpDate = rxDateTime->m_xDateField->get_date();
2460 tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2461 util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2462 aTmpTime.GetMin(), aTmpTime.GetHour(),
2463 aTmpDate.GetDay(), aTmpDate.GetMonth(),
2464 aTmpDate.GetYear(), true );
2465 seqValueRange[k] = aDateTime;
2466 ++k;
2468 aPropertiesSeqRange[i].Value <<= seqValue;
2470 else
2472 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2473 auto seqValueRange = asNonConstRange(seqValue);
2474 sal_Int32 k = 0;
2475 for ( const auto& rxValue : pLine->m_aValues )
2477 seqValueRange[k] = rxValue->m_xValueEdit->get_text();
2478 ++k;
2480 aPropertiesSeqRange[i].Value <<= seqValue;
2483 ++i;
2486 return aPropertiesSeq;
2489 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2490 : m_aPropertiesWin(rBuilder.weld_container(u"CmisWindow"_ustr))
2491 , m_xScrolledWindow(rBuilder.weld_scrolled_window(u"CmisScroll"_ustr))
2493 // set height to something small and force it to take the size
2494 // dictated by the other pages
2495 m_xScrolledWindow->set_size_request(-1, 42);
2498 void CmisPropertiesControl::ClearAllLines()
2500 m_aPropertiesWin.ClearAllLines();
2503 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2504 const OUString& sType, const bool bUpdatable,
2505 const bool bRequired, const bool bMultiValued,
2506 const bool bOpenChoice, Any& aChoices, Any const & rAny
2509 m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2510 bOpenChoice, aChoices, rAny );
2513 // class SfxCmisPropertiesPage -----------------------------------------
2514 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2515 : SfxTabPage(pPage, pController, u"sfx/ui/cmisinfopage.ui"_ustr, u"CmisInfoPage"_ustr, &rItemSet)
2516 , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2520 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2522 m_xPropertiesCtrl.reset();
2525 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2527 const SfxDocumentInfoItem* pItem = nullptr;
2528 SfxDocumentInfoItem* pInfo = nullptr;
2529 bool bMustDelete = false;
2531 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2533 pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2534 if (!pItem)
2535 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2536 else
2538 bMustDelete = true;
2539 pInfo = new SfxDocumentInfoItem( *pItem );
2543 sal_Int32 modifiedNum = 0;
2544 if ( pInfo )
2546 Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2547 Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2549 std::vector< document::CmisProperty > changedProps;
2550 for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2552 if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2554 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2556 Sequence< util::DateTime > oldValue;
2557 aOldProps[i].Value >>= oldValue;
2558 // We only edit hours and minutes
2559 // don't compare NanoSeconds and Seconds
2560 for ( auto& rDateTime : asNonConstRange(oldValue) )
2562 rDateTime.NanoSeconds = 0;
2563 rDateTime.Seconds = 0;
2565 Sequence< util::DateTime > newValue;
2566 aNewProps[i].Value >>= newValue;
2567 if ( oldValue != newValue )
2569 modifiedNum++;
2570 changedProps.push_back( aNewProps[i] );
2573 else if ( aOldProps[i].Value != aNewProps[i].Value )
2575 modifiedNum++;
2576 changedProps.push_back( aNewProps[i] );
2580 Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2581 pInfo->SetCmisProperties( aModifiedProps );
2582 rSet->Put( *pInfo );
2583 if ( bMustDelete )
2584 delete pInfo;
2587 return modifiedNum;
2590 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2592 m_xPropertiesCtrl->ClearAllLines();
2593 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2594 uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2595 for ( auto& rCmisProp : asNonConstRange(aCmisProps) )
2597 m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2598 rCmisProp.Name,
2599 rCmisProp.Type,
2600 rCmisProp.Updatable,
2601 rCmisProp.Required,
2602 rCmisProp.MultiValued,
2603 rCmisProp.OpenChoice,
2604 rCmisProp.Choices,
2605 rCmisProp.Value);
2609 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2611 return DeactivateRC::LeavePage;
2614 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2616 return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2619 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */