LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / sfx2 / source / dialog / dinfdlg.cxx
blob799d8fbd3168f1a13687a07057b27475873872b0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svl/eitem.hxx>
21 #include <tools/datetime.hxx>
22 #include <tools/debug.hxx>
23 #include <tools/urlobj.hxx>
24 #include <vcl/svapp.hxx>
25 #include <vcl/weld.hxx>
26 #include <vcl/weldutils.hxx>
27 #include <unotools/datetime.hxx>
28 #include <unotools/localedatawrapper.hxx>
29 #include <unotools/cmdoptions.hxx>
30 #include <comphelper/processfactory.hxx>
31 #include <comphelper/propertyvalue.hxx>
32 #include <comphelper/stl_types.hxx>
33 #include <comphelper/xmlsechelper.hxx>
34 #include <unotools/useroptions.hxx>
35 #include <svtools/ctrlbox.hxx>
36 #include <svtools/imagemgr.hxx>
37 #include <sal/log.hxx>
38 #include <osl/diagnose.h>
39 #include <osl/file.hxx>
40 #include <comphelper/lok.hxx>
42 #include <memory>
44 #include <comphelper/sequence.hxx>
45 #include <comphelper/string.hxx>
46 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
47 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
48 #include <unotools/syslocale.hxx>
49 #include <rtl/math.hxx>
50 #include <com/sun/star/beans/PropertyAttribute.hpp>
51 #include <com/sun/star/beans/XPropertyContainer.hpp>
52 #include <com/sun/star/beans/XPropertySet.hpp>
53 #include <com/sun/star/util/DateTime.hpp>
54 #include <com/sun/star/util/Date.hpp>
55 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
56 #include <com/sun/star/util/DateWithTimezone.hpp>
57 #include <com/sun/star/util/Duration.hpp>
58 #include <com/sun/star/document/XDocumentProperties.hpp>
59 #include <com/sun/star/document/CmisProperty.hpp>
60 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
62 #include <vcl/timer.hxx>
63 #include <vcl/settings.hxx>
64 #include <sfx2/sfxresid.hxx>
65 #include <sfx2/frame.hxx>
66 #include <sfx2/filedlghelper.hxx>
67 #include <sfx2/dinfdlg.hxx>
68 #include <sfx2/sfxsids.hrc>
69 #include <helper.hxx>
70 #include <sfx2/objsh.hxx>
71 #include <sfx2/docfile.hxx>
72 #include <vcl/abstdlg.hxx>
74 #include <documentfontsdialog.hxx>
75 #include <dinfdlg.hrc>
76 #include <sfx2/strings.hrc>
77 #include <strings.hxx>
78 #include <tools/diagnose_ex.h>
79 #include "securitypage.hxx"
81 #include <algorithm>
83 using namespace ::com::sun::star;
84 using namespace ::com::sun::star::uno;
86 struct CustomProperty
88 OUString m_sName;
89 css::uno::Any m_aValue;
91 CustomProperty( const OUString& sName, const css::uno::Any& rValue ) :
92 m_sName( sName ), m_aValue( rValue ) {}
94 bool operator==(const CustomProperty& rProp) const
96 return m_sName == rProp.m_sName && m_aValue == rProp.m_aValue;
100 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
102 namespace {
104 OUString CreateSizeText( sal_Int64 nSize )
106 OUString aUnitStr = " " + SfxResId(STR_BYTES);
107 sal_Int64 nSize1 = nSize;
108 sal_Int64 nSize2 = nSize1;
109 sal_Int64 nMega = 1024 * 1024;
110 sal_Int64 nGiga = nMega * 1024;
111 double fSize = nSize;
112 int nDec = 0;
114 if ( nSize1 >= 10000 && nSize1 < nMega )
116 nSize1 /= 1024;
117 aUnitStr = " " + SfxResId(STR_KB);
118 fSize /= 1024;
119 nDec = 0;
121 else if ( nSize1 >= nMega && nSize1 < nGiga )
123 nSize1 /= nMega;
124 aUnitStr = " " + SfxResId(STR_MB);
125 fSize /= nMega;
126 nDec = 2;
128 else if ( nSize1 >= nGiga )
130 nSize1 /= nGiga;
131 aUnitStr = " " + SfxResId(STR_GB);
132 fSize /= nGiga;
133 nDec = 3;
135 const SvtSysLocale aSysLocale;
136 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
137 OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
138 if ( nSize1 < nSize2 )
140 aSizeStr = ::rtl::math::doubleToUString( fSize,
141 rtl_math_StringFormat_F, nDec,
142 rLocaleWrapper.getNumDecimalSep()[0] )
143 + aUnitStr
144 + " ("
145 + rLocaleWrapper.getNum( nSize2, 0 )
146 + " "
147 + SfxResId(STR_BYTES)
148 + ")";
150 return aSizeStr;
153 OUString ConvertDateTime_Impl( std::u16string_view rName,
154 const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
156 Date aD(uDT);
157 tools::Time aT(uDT);
158 static const OUStringLiteral aDelim( u", " );
159 OUString aStr = rWrapper.getDate( aD )
160 + aDelim
161 + rWrapper.getTime( aT );
162 OUString aAuthor = comphelper::string::stripStart(rName, ' ');
163 if (!aAuthor.isEmpty())
165 aStr += aDelim + aAuthor;
167 return aStr;
173 SfxDocumentInfoItem::SfxDocumentInfoItem()
174 : m_AutoloadDelay(0)
175 , m_isAutoloadEnabled(false)
176 , m_EditingCycles(0)
177 , m_EditingDuration(0)
178 , m_bHasTemplate( true )
179 , m_bDeleteUserData( false )
180 , m_bUseUserData( true )
181 , m_bUseThumbnailSave( true )
185 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
186 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
187 const uno::Sequence<document::CmisProperty>& i_cmisProps,
188 bool bIs, bool _bIs )
189 : SfxStringItem( SID_DOCINFO, rFile )
190 , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
191 , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
192 , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
193 , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
194 , m_TemplateName( i_xDocProps->getTemplateName() )
195 , m_Author( i_xDocProps->getAuthor() )
196 , m_CreationDate( i_xDocProps->getCreationDate() )
197 , m_ModifiedBy( i_xDocProps->getModifiedBy() )
198 , m_ModificationDate( i_xDocProps->getModificationDate() )
199 , m_PrintedBy( i_xDocProps->getPrintedBy() )
200 , m_PrintDate( i_xDocProps->getPrintDate() )
201 , m_EditingCycles( i_xDocProps->getEditingCycles() )
202 , m_EditingDuration( i_xDocProps->getEditingDuration() )
203 , m_Description( i_xDocProps->getDescription() )
204 , m_Keywords( ::comphelper::string::convertCommaSeparated(
205 i_xDocProps->getKeywords()) )
206 , m_Subject( i_xDocProps->getSubject() )
207 , m_Title( i_xDocProps->getTitle() )
208 , m_bHasTemplate( true )
209 , m_bDeleteUserData( false )
210 , m_bUseUserData( bIs )
211 , m_bUseThumbnailSave( _bIs )
215 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
216 if ( xContainer.is() )
218 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
219 const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
220 for ( const beans::Property& rProp : lProps )
222 // "fix" property? => not a custom property => ignore it!
223 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
225 SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
226 continue;
229 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
230 AddCustomProperty( rProp.Name, aValue );
234 // get CMIS properties
235 m_aCmisProperties = i_cmisProps;
237 catch ( Exception& ) {}
241 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
242 : SfxStringItem( rItem )
243 , m_AutoloadDelay( rItem.getAutoloadDelay() )
244 , m_AutoloadURL( rItem.getAutoloadURL() )
245 , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
246 , m_DefaultTarget( rItem.getDefaultTarget() )
247 , m_TemplateName( rItem.getTemplateName() )
248 , m_Author( rItem.getAuthor() )
249 , m_CreationDate( rItem.getCreationDate() )
250 , m_ModifiedBy( rItem.getModifiedBy() )
251 , m_ModificationDate( rItem.getModificationDate() )
252 , m_PrintedBy( rItem.getPrintedBy() )
253 , m_PrintDate( rItem.getPrintDate() )
254 , m_EditingCycles( rItem.getEditingCycles() )
255 , m_EditingDuration( rItem.getEditingDuration() )
256 , m_Description( rItem.getDescription() )
257 , m_Keywords( rItem.getKeywords() )
258 , m_Subject( rItem.getSubject() )
259 , m_Title( rItem.getTitle() )
260 , m_bHasTemplate( rItem.m_bHasTemplate )
261 , m_bDeleteUserData( rItem.m_bDeleteUserData )
262 , m_bUseUserData( rItem.m_bUseUserData )
263 , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
265 for (auto const & pOtherProp : rItem.m_aCustomProperties)
267 AddCustomProperty( pOtherProp->m_sName, pOtherProp->m_aValue );
270 m_aCmisProperties = rItem.m_aCmisProperties;
273 SfxDocumentInfoItem::~SfxDocumentInfoItem()
275 ClearCustomProperties();
278 SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
280 return new SfxDocumentInfoItem( *this );
283 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
285 if (!SfxStringItem::operator==(rItem))
286 return false;
287 const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
289 return
290 m_AutoloadDelay == rInfoItem.m_AutoloadDelay &&
291 m_AutoloadURL == rInfoItem.m_AutoloadURL &&
292 m_isAutoloadEnabled == rInfoItem.m_isAutoloadEnabled &&
293 m_DefaultTarget == rInfoItem.m_DefaultTarget &&
294 m_Author == rInfoItem.m_Author &&
295 m_CreationDate == rInfoItem.m_CreationDate &&
296 m_ModifiedBy == rInfoItem.m_ModifiedBy &&
297 m_ModificationDate == rInfoItem.m_ModificationDate &&
298 m_PrintedBy == rInfoItem.m_PrintedBy &&
299 m_PrintDate == rInfoItem.m_PrintDate &&
300 m_EditingCycles == rInfoItem.m_EditingCycles &&
301 m_EditingDuration == rInfoItem.m_EditingDuration &&
302 m_Description == rInfoItem.m_Description &&
303 m_Keywords == rInfoItem.m_Keywords &&
304 m_Subject == rInfoItem.m_Subject &&
305 m_Title == rInfoItem.m_Title &&
306 comphelper::ContainerUniquePtrEquals(m_aCustomProperties, rInfoItem.m_aCustomProperties) &&
307 m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
311 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
313 m_Author = i_rAuthor;
314 DateTime now( DateTime::SYSTEM );
315 m_CreationDate = now.GetUNODateTime();
316 m_ModifiedBy = OUString();
317 m_PrintedBy = OUString();
318 m_ModificationDate = util::DateTime();
319 m_PrintDate = util::DateTime();
320 m_EditingDuration = 0;
321 m_EditingCycles = 1;
325 void SfxDocumentInfoItem::UpdateDocumentInfo(
326 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
327 bool i_bDoNotUpdateUserDefined) const
329 if (isAutoloadEnabled()) {
330 i_xDocProps->setAutoloadSecs(getAutoloadDelay());
331 i_xDocProps->setAutoloadURL(getAutoloadURL());
332 } else {
333 i_xDocProps->setAutoloadSecs(0);
334 i_xDocProps->setAutoloadURL(OUString());
336 i_xDocProps->setDefaultTarget(getDefaultTarget());
337 i_xDocProps->setAuthor(getAuthor());
338 i_xDocProps->setCreationDate(getCreationDate());
339 i_xDocProps->setModifiedBy(getModifiedBy());
340 i_xDocProps->setModificationDate(getModificationDate());
341 i_xDocProps->setPrintedBy(getPrintedBy());
342 i_xDocProps->setPrintDate(getPrintDate());
343 i_xDocProps->setEditingCycles(getEditingCycles());
344 i_xDocProps->setEditingDuration(getEditingDuration());
345 i_xDocProps->setDescription(getDescription());
346 i_xDocProps->setKeywords(
347 ::comphelper::string::convertCommaSeparated(getKeywords()));
348 i_xDocProps->setSubject(getSubject());
349 i_xDocProps->setTitle(getTitle());
351 // this is necessary in case of replaying a recorded macro:
352 // in this case, the macro may contain the 4 old user-defined DocumentInfo
353 // fields, but not any of the DocumentInfo properties;
354 // as a consequence, most of the UserDefined properties of the
355 // DocumentProperties would be summarily deleted here, which does not
356 // seem like a good idea.
357 if (i_bDoNotUpdateUserDefined)
358 return;
362 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
363 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
364 Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
365 const Sequence< beans::Property > lProps = xSetInfo->getProperties();
366 for ( const beans::Property& rProp : lProps )
368 if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
370 xContainer->removeProperty( rProp.Name );
374 for (auto const & pProp : m_aCustomProperties)
378 xContainer->addProperty( pProp->m_sName,
379 beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
381 catch ( Exception const & )
383 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
387 catch ( Exception const & )
389 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
394 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
396 m_bDeleteUserData = bSet;
400 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
402 m_bUseUserData = bSet;
405 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
407 m_bUseThumbnailSave = bSet;
410 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
412 std::vector< std::unique_ptr<CustomProperty> > aRet;
413 for (auto const & pOtherProp : m_aCustomProperties)
415 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
416 pOtherProp->m_aValue ));
417 aRet.push_back( std::move(pProp) );
420 return aRet;
423 void SfxDocumentInfoItem::ClearCustomProperties()
425 m_aCustomProperties.clear();
428 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
430 std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
431 m_aCustomProperties.push_back( std::move(pProp) );
435 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
437 m_aCmisProperties = cmisProps;
440 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
442 OUString aValue;
443 sal_Int32 nValue = 0;
444 bool bValue = false;
445 bool bIsInt = false;
446 bool bIsString = false;
447 nMemberId &= ~CONVERT_TWIPS;
448 switch ( nMemberId )
450 case MID_DOCINFO_USEUSERDATA:
451 bValue = IsUseUserData();
452 break;
453 case MID_DOCINFO_USETHUMBNAILSAVE:
454 bValue = IsUseThumbnailSave();
455 break;
456 case MID_DOCINFO_DELETEUSERDATA:
457 bValue = m_bDeleteUserData;
458 break;
459 case MID_DOCINFO_AUTOLOADENABLED:
460 bValue = isAutoloadEnabled();
461 break;
462 case MID_DOCINFO_AUTOLOADSECS:
463 bIsInt = true;
464 nValue = getAutoloadDelay();
465 break;
466 case MID_DOCINFO_AUTOLOADURL:
467 bIsString = true;
468 aValue = getAutoloadURL();
469 break;
470 case MID_DOCINFO_DEFAULTTARGET:
471 bIsString = true;
472 aValue = getDefaultTarget();
473 break;
474 case MID_DOCINFO_DESCRIPTION:
475 bIsString = true;
476 aValue = getDescription();
477 break;
478 case MID_DOCINFO_KEYWORDS:
479 bIsString = true;
480 aValue = getKeywords();
481 break;
482 case MID_DOCINFO_SUBJECT:
483 bIsString = true;
484 aValue = getSubject();
485 break;
486 case MID_DOCINFO_TITLE:
487 bIsString = true;
488 aValue = getTitle();
489 break;
490 default:
491 OSL_FAIL("Wrong MemberId!");
492 return false;
495 if ( bIsString )
496 rVal <<= aValue;
497 else if ( bIsInt )
498 rVal <<= nValue;
499 else
500 rVal <<= bValue;
501 return true;
504 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
506 OUString aValue;
507 sal_Int32 nValue=0;
508 bool bValue = false;
509 bool bRet = false;
510 nMemberId &= ~CONVERT_TWIPS;
511 switch ( nMemberId )
513 case MID_DOCINFO_USEUSERDATA:
514 bRet = (rVal >>= bValue);
515 if ( bRet )
516 SetUseUserData( bValue );
517 break;
518 case MID_DOCINFO_USETHUMBNAILSAVE:
519 bRet = (rVal >>=bValue);
520 if ( bRet )
521 SetUseThumbnailSave( bValue );
522 break;
523 case MID_DOCINFO_DELETEUSERDATA:
524 // QUESTION: deleting user data was done here; seems to be superfluous!
525 bRet = (rVal >>= bValue);
526 if ( bRet )
527 SetDeleteUserData( bValue );
528 break;
529 case MID_DOCINFO_AUTOLOADENABLED:
530 bRet = (rVal >>= bValue);
531 if ( bRet )
532 m_isAutoloadEnabled = bValue;
533 break;
534 case MID_DOCINFO_AUTOLOADSECS:
535 bRet = (rVal >>= nValue);
536 if ( bRet )
537 m_AutoloadDelay = nValue;
538 break;
539 case MID_DOCINFO_AUTOLOADURL:
540 bRet = (rVal >>= aValue);
541 if ( bRet )
542 m_AutoloadURL = aValue;
543 break;
544 case MID_DOCINFO_DEFAULTTARGET:
545 bRet = (rVal >>= aValue);
546 if ( bRet )
547 m_DefaultTarget = aValue;
548 break;
549 case MID_DOCINFO_DESCRIPTION:
550 bRet = (rVal >>= aValue);
551 if ( bRet )
552 setDescription(aValue);
553 break;
554 case MID_DOCINFO_KEYWORDS:
555 bRet = (rVal >>= aValue);
556 if ( bRet )
557 setKeywords(aValue);
558 break;
559 case MID_DOCINFO_SUBJECT:
560 bRet = (rVal >>= aValue);
561 if ( bRet )
562 setSubject(aValue);
563 break;
564 case MID_DOCINFO_TITLE:
565 bRet = (rVal >>= aValue);
566 if ( bRet )
567 setTitle(aValue);
568 break;
569 default:
570 OSL_FAIL("Wrong MemberId!");
571 return false;
574 return bRet;
577 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
578 : SfxTabPage(pPage, pController, "sfx/ui/descriptioninfopage.ui", "DescriptionInfoPage", &rItemSet)
579 , m_pInfoItem(nullptr)
580 , m_xTitleEd(m_xBuilder->weld_entry("title"))
581 , m_xThemaEd(m_xBuilder->weld_entry("subject"))
582 , m_xKeywordsEd(m_xBuilder->weld_entry("keywords"))
583 , m_xCommentEd(m_xBuilder->weld_text_view("comments"))
585 m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
586 m_xCommentEd->get_height_rows(16));
589 SfxDocumentDescPage::~SfxDocumentDescPage()
593 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
595 return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
598 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
600 // Test whether a change is present
601 const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
602 const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
603 const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
604 const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
605 if ( !( bTitleMod || bThemeMod || bKeywordsMod || bCommentMod ) )
607 return false;
610 // Generating the output data
611 const SfxPoolItem* pItem = nullptr;
612 SfxDocumentInfoItem* pInfo = nullptr;
613 const SfxItemSet* pExSet = GetDialogExampleSet();
615 if ( pExSet && SfxItemState::SET != pExSet->GetItemState( SID_DOCINFO, true, &pItem ) )
616 pInfo = m_pInfoItem;
617 else if ( pItem )
618 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem *>(pItem) );
620 if ( !pInfo )
622 SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
623 return false;
626 if ( bTitleMod )
628 pInfo->setTitle( m_xTitleEd->get_text() );
630 if ( bThemeMod )
632 pInfo->setSubject( m_xThemaEd->get_text() );
634 if ( bKeywordsMod )
636 pInfo->setKeywords( m_xKeywordsEd->get_text() );
638 if ( bCommentMod )
640 pInfo->setDescription( m_xCommentEd->get_text() );
642 rSet->Put( *pInfo );
643 if ( pInfo != m_pInfoItem )
645 delete pInfo;
648 return true;
651 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
653 m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
655 m_xTitleEd->set_text(m_pInfoItem->getTitle());
656 m_xThemaEd->set_text(m_pInfoItem->getSubject());
657 m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
658 m_xCommentEd->set_text(m_pInfoItem->getDescription());
660 m_xTitleEd->save_value();
661 m_xThemaEd->save_value();
662 m_xKeywordsEd->save_value();
663 m_xCommentEd->save_value();
665 const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
666 if (pROItem && pROItem->GetValue())
668 m_xTitleEd->set_editable(false);
669 m_xThemaEd->set_editable(false);
670 m_xKeywordsEd->set_editable(false);
671 m_xCommentEd->set_editable(false);
675 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
676 : SfxTabPage(pPage, pController, "sfx/ui/documentinfopage.ui", "DocumentInfoPage", &rItemSet)
677 , bEnableUseUserData( false )
678 , bHandleDelete( false )
679 , m_xBmp(m_xBuilder->weld_image("icon"))
680 , m_xNameED(m_xBuilder->weld_label("nameed"))
681 , m_xChangePassBtn(m_xBuilder->weld_button("changepass"))
682 , m_xShowTypeFT(m_xBuilder->weld_label("showtype"))
683 , m_xFileValEd(m_xBuilder->weld_link_button("showlocation"))
684 , m_xShowSizeFT(m_xBuilder->weld_label("showsize"))
685 , m_xCreateValFt(m_xBuilder->weld_label("showcreate"))
686 , m_xChangeValFt(m_xBuilder->weld_label("showmodify"))
687 , m_xSignedValFt(m_xBuilder->weld_label("showsigned"))
688 , m_xSignatureBtn(m_xBuilder->weld_button("signature"))
689 , m_xPrintValFt(m_xBuilder->weld_label("showprint"))
690 , m_xTimeLogValFt(m_xBuilder->weld_label("showedittime"))
691 , m_xDocNoValFt(m_xBuilder->weld_label("showrevision"))
692 , m_xUseUserDataCB(m_xBuilder->weld_check_button("userdatacb"))
693 , m_xDeleteBtn(m_xBuilder->weld_button("reset"))
694 , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button("thumbnailsavecb"))
695 , m_xTemplFt(m_xBuilder->weld_label("templateft"))
696 , m_xTemplValFt(m_xBuilder->weld_label("showtemplate"))
697 , m_xImagePreferredDpiCheckButton(m_xBuilder->weld_check_button("image-preferred-dpi-checkbutton"))
698 , m_xImagePreferredDpiComboBox(m_xBuilder->weld_combo_box("image-preferred-dpi-combobox"))
700 m_aUnknownSize = m_xShowSizeFT->get_label();
701 m_xShowSizeFT->set_label(OUString());
703 m_aMultiSignedStr = m_xSignedValFt->get_label();
704 m_xSignedValFt->set_label(OUString());
706 ImplUpdateSignatures();
707 ImplCheckPasswordState();
708 m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
709 m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
710 if (comphelper::LibreOfficeKit::isActive())
711 m_xSignatureBtn->hide();
712 m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
713 m_xImagePreferredDpiCheckButton->connect_toggled(LINK(this, SfxDocumentPage, ImagePreferredDPICheckBoxClicked));
715 // [i96288] Check if the document signature command is enabled
716 // on the main list enable/disable the pushbutton accordingly
717 SvtCommandOptions aCmdOptions;
718 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "Signature" ) )
719 m_xSignatureBtn->set_sensitive(false);
722 SfxDocumentPage::~SfxDocumentPage()
724 if (m_xPasswordDialog)
726 m_xPasswordDialog->Response(RET_CANCEL);
727 m_xPasswordDialog.clear();
731 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
733 OUString aName;
734 if (bEnableUseUserData && m_xUseUserDataCB->get_active())
735 aName = SvtUserOptions().GetFullName();
736 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
737 DateTime now( DateTime::SYSTEM );
738 util::DateTime uDT( now.GetUNODateTime() );
739 m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
740 m_xChangeValFt->set_label( "" );
741 m_xPrintValFt->set_label( "" );
742 const tools::Time aTime( 0 );
743 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aTime ) );
744 m_xDocNoValFt->set_label(OUString('1'));
745 bHandleDelete = true;
748 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
750 SfxObjectShell* pDoc = SfxObjectShell::Current();
751 if( pDoc )
753 pDoc->SignDocumentContent(GetFrameWeld());
755 ImplUpdateSignatures();
759 IMPL_LINK_NOARG(SfxDocumentPage, ImagePreferredDPICheckBoxClicked, weld::Toggleable&, void)
761 bool bEnabled = m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE;
762 m_xImagePreferredDpiComboBox->set_sensitive(bEnabled);
765 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
767 SfxObjectShell* pShell = SfxObjectShell::Current();
770 if (!pShell)
771 break;
772 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
773 if (!pMedSet)
774 break;
775 std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
776 if (!pFilter)
777 break;
778 if (comphelper::LibreOfficeKit::isActive())
780 // MS Types support max len of 15 characters while OOXML is "unlimited"
781 const sal_uInt16 maxPwdLen = sfx2::IsMSType(pFilter) && !sfx2::IsOOXML(pFilter) ? 15 : 0;
782 // handle the pwd dialog asynchronously
783 VclAbstractDialogFactory * pFact = VclAbstractDialogFactory::Create();
784 m_xPasswordDialog = pFact->CreatePasswordToOpenModifyDialog(GetFrameWeld(), maxPwdLen, false);
785 m_xPasswordDialog->AllowEmpty(); // needed to remove password
786 m_xPasswordDialog->StartExecuteAsync([this, pFilter, pMedSet, pShell](sal_Int32 nResult)
788 if (nResult == RET_OK)
790 sfx2::SetPassword(pFilter, pMedSet, m_xPasswordDialog->GetPasswordToOpen(),
791 m_xPasswordDialog->GetPasswordToOpen(), true);
792 pShell->SetModified();
794 m_xPasswordDialog->disposeOnce();
796 } else {
797 sfx2::RequestPassword(pFilter, OUString(), pMedSet, GetFrameWeld()->GetXWindow());
798 pShell->SetModified();
801 while (false);
804 void SfxDocumentPage::ImplUpdateSignatures()
806 SfxObjectShell* pDoc = SfxObjectShell::Current();
807 if ( !pDoc )
808 return;
810 SfxMedium* pMedium = pDoc->GetMedium();
811 if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
812 return;
814 Reference< security::XDocumentDigitalSignatures > xD;
817 xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
818 xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
820 catch ( const css::uno::DeploymentException& )
823 OUString s;
824 Sequence< security::DocumentSignatureInformation > aInfos;
826 if ( xD.is() )
827 aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
828 uno::Reference< io::XInputStream >() );
829 if ( aInfos.getLength() > 1 )
830 s = m_aMultiSignedStr;
831 else if ( aInfos.getLength() == 1 )
833 const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
834 s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
835 comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
837 m_xSignedValFt->set_label(s);
840 void SfxDocumentPage::ImplCheckPasswordState()
842 SfxObjectShell* pShell = SfxObjectShell::Current();
845 if (!pShell)
846 break;
847 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
848 if (!pMedSet)
849 break;
850 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pMedSet, SID_ENCRYPTIONDATA, false);
851 uno::Sequence< beans::NamedValue > aEncryptionData;
852 if (pEncryptionDataItem)
853 pEncryptionDataItem->GetValue() >>= aEncryptionData;
854 else
855 break;
857 if (!aEncryptionData.hasElements())
858 break;
859 m_xChangePassBtn->set_sensitive(true);
860 return;
862 while (false);
863 m_xChangePassBtn->set_sensitive(comphelper::LibreOfficeKit::isActive());
866 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
868 return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
871 void SfxDocumentPage::EnableUseUserData()
873 bEnableUseUserData = true;
874 m_xUseUserDataCB->show();
875 m_xDeleteBtn->show();
878 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
880 bool bRet = false;
882 if ( !bHandleDelete && bEnableUseUserData &&
883 m_xUseUserDataCB->get_state_changed_from_saved() )
885 const SfxItemSet* pExpSet = GetDialogExampleSet();
886 const SfxPoolItem* pItem;
888 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
890 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
891 bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
892 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
893 rSet->Put( *pInfoItem );
894 bRet = true;
898 if ( bHandleDelete )
900 const SfxItemSet* pExpSet = GetDialogExampleSet();
901 const SfxPoolItem* pItem;
902 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
904 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
905 bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
906 SfxDocumentInfoItem newItem( *pInfoItem );
907 newItem.resetUserData( bUseAuthor
908 ? SvtUserOptions().GetFullName()
909 : OUString() );
910 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
911 newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
913 newItem.SetDeleteUserData( true );
914 rSet->Put( newItem );
915 bRet = true;
919 if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
921 const SfxItemSet* pExpSet = GetDialogExampleSet();
922 const SfxPoolItem* pItem;
924 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
926 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
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::makeAny(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 const SfxPoolItem* pItem = nullptr;
1168 OUString aTitle(m_xDialog->get_title());
1169 if ( SfxItemState::SET !=
1170 rItemSet.GetItemState( SID_EXPLORER_PROPS_START, false, &pItem ) )
1172 // File name
1173 const OUString& aFile( rInfoItem.GetValue() );
1175 INetURLObject aURL;
1176 aURL.SetSmartProtocol( INetProtocol::File );
1177 aURL.SetSmartURL( aFile);
1178 if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1180 OUString aLastName( aURL.GetLastName() );
1181 if ( !aLastName.isEmpty() )
1182 aTitle = aTitle.replaceFirst("%1", aLastName);
1183 else
1184 aTitle = aTitle.replaceFirst("%1", aFile);
1186 else
1187 aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1189 else
1191 DBG_ASSERT( dynamic_cast<const SfxStringItem *>(pItem) != nullptr,
1192 "SfxDocumentInfoDialog:<SfxStringItem> expected" );
1193 aTitle = aTitle.replaceFirst("%1", static_cast<const SfxStringItem*>(pItem)->GetValue());
1195 m_xDialog->set_title(aTitle);
1197 // Property Pages
1198 AddTabPage("general", SfxDocumentPage::Create, nullptr);
1199 AddTabPage("description", SfxDocumentDescPage::Create, nullptr);
1201 if (!comphelper::LibreOfficeKit::isActive())
1202 AddTabPage("customprops", SfxCustomPropertiesPage::Create, nullptr);
1203 else
1204 RemoveTabPage("customprops");
1206 if (rInfoItem.isCmisDocument())
1207 AddTabPage("cmisprops", SfxCmisPropertiesPage::Create, nullptr);
1208 else
1209 RemoveTabPage("cmisprops");
1210 // Disable security page for online as not fully asynced yet
1211 if (!comphelper::LibreOfficeKit::isActive())
1212 AddTabPage("security", SfxSecurityPage::Create, nullptr);
1213 else
1214 RemoveTabPage("security");
1217 void SfxDocumentInfoDialog::PageCreated(const OString& rId, SfxTabPage &rPage)
1219 if (rId == "general")
1220 static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1223 void SfxDocumentInfoDialog::AddFontTabPage()
1225 AddTabPage("font", SfxResId(STR_FONT_TABPAGE), SfxDocumentFontsPage::Create);
1228 // class CustomPropertiesYesNoButton -------------------------------------
1230 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1231 std::unique_ptr<weld::RadioButton> xYesButton,
1232 std::unique_ptr<weld::RadioButton> xNoButton)
1233 : m_xTopLevel(std::move(xTopLevel))
1234 , m_xYesButton(std::move(xYesButton))
1235 , m_xNoButton(std::move(xNoButton))
1237 CheckNo();
1240 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1245 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1246 : GenericDialogController(pParent, "sfx/ui/editdurationdialog.ui", "EditDurationDialog")
1247 , m_xNegativeCB(m_xBuilder->weld_check_button("negative"))
1248 , m_xYearNF(m_xBuilder->weld_spin_button("years"))
1249 , m_xMonthNF(m_xBuilder->weld_spin_button("months"))
1250 , m_xDayNF(m_xBuilder->weld_spin_button("days"))
1251 , m_xHourNF(m_xBuilder->weld_spin_button("hours"))
1252 , m_xMinuteNF(m_xBuilder->weld_spin_button("minutes"))
1253 , m_xSecondNF(m_xBuilder->weld_spin_button("seconds"))
1254 , m_xMSecondNF(m_xBuilder->weld_spin_button("milliseconds"))
1256 m_xNegativeCB->set_active(rDuration.Negative);
1257 m_xYearNF->set_value(rDuration.Years);
1258 m_xMonthNF->set_value(rDuration.Months);
1259 m_xDayNF->set_value(rDuration.Days);
1260 m_xHourNF->set_value(rDuration.Hours);
1261 m_xMinuteNF->set_value(rDuration.Minutes);
1262 m_xSecondNF->set_value(rDuration.Seconds);
1263 m_xMSecondNF->set_value(rDuration.NanoSeconds);
1266 util::Duration DurationDialog_Impl::GetDuration() const
1268 util::Duration aRet;
1269 aRet.Negative = m_xNegativeCB->get_active();
1270 aRet.Years = m_xYearNF->get_value();
1271 aRet.Months = m_xMonthNF->get_value();
1272 aRet.Days = m_xDayNF->get_value();
1273 aRet.Hours = m_xHourNF->get_value();
1274 aRet.Minutes = m_xMinuteNF->get_value();
1275 aRet.Seconds = m_xSecondNF->get_value();
1276 aRet.NanoSeconds = m_xMSecondNF->get_value();
1277 return aRet;
1280 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1281 std::unique_ptr<weld::Button> xEditButton)
1282 : m_xEntry(std::move(xEntry))
1283 , m_xEditButton(std::move(xEditButton))
1285 m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1286 SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1289 void CustomPropertiesDurationField::set_visible(bool bVisible)
1291 m_xEntry->set_visible(bVisible);
1292 m_xEditButton->set_visible(bVisible);
1295 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1297 m_aDuration = rDuration;
1298 OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1299 SfxResId(SFX_ST_DURATION_FORMAT);
1300 sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1301 sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1302 sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days ) );
1303 sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours ) );
1304 sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1305 sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1306 m_xEntry->set_text(sText);
1309 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1311 m_xDurationDialog = std::make_shared<DurationDialog_Impl>(&rButton, GetDuration());
1312 weld::DialogController::runAsync(m_xDurationDialog, [&](sal_Int32 response)
1314 if (response == RET_OK)
1316 SetDuration(m_xDurationDialog->GetDuration());
1321 CustomPropertiesDurationField::~CustomPropertiesDurationField()
1323 if (m_xDurationDialog)
1324 m_xDurationDialog->response(RET_CANCEL);
1327 namespace
1329 void fillNameBox(weld::ComboBox& rNameBox)
1331 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1332 rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1333 Size aSize(rNameBox.get_preferred_size());
1334 rNameBox.set_size_request(aSize.Width(), aSize.Height());
1337 void fillTypeBox(weld::ComboBox& rTypeBox)
1339 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1341 OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1342 rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1344 rTypeBox.set_active(0);
1345 Size aSize(rTypeBox.get_preferred_size());
1346 rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1350 // struct CustomPropertyLine ---------------------------------------------
1351 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1352 : m_pParent(pParent)
1353 , m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/linefragment.ui"))
1354 , m_xLine(m_xBuilder->weld_container("lineentry"))
1355 , m_xNameBox(m_xBuilder->weld_combo_box("namebox"))
1356 , m_xTypeBox(m_xBuilder->weld_combo_box("typebox"))
1357 , m_xValueEdit(m_xBuilder->weld_entry("valueedit"))
1358 , m_xDateTimeBox(m_xBuilder->weld_widget("datetimebox"))
1359 , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date"))))
1360 , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button("time")))
1361 , m_xDurationBox(m_xBuilder->weld_widget("durationbox"))
1362 , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry("duration"),
1363 m_xBuilder->weld_button("durationbutton")))
1364 , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget("yesno"),
1365 m_xBuilder->weld_radio_button("yes"),
1366 m_xBuilder->weld_radio_button("no")))
1367 , m_xRemoveButton(m_xBuilder->weld_button("remove"))
1368 , m_bTypeLostFocus( false )
1370 fillNameBox(*m_xNameBox);
1371 fillTypeBox(*m_xTypeBox);
1373 m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1374 m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1375 m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1376 //add lose focus handlers of date/time fields
1377 m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1380 void CustomPropertyLine::Clear()
1382 m_xNameBox->set_active(-1);
1383 m_xValueEdit->set_text(OUString());
1387 void CustomPropertyLine::Hide()
1389 m_xLine->hide();
1392 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1393 weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1394 : m_nHeight(0)
1395 , m_nLineHeight(0)
1396 , m_nScrollPos(0)
1397 , m_pCurrentLine(nullptr)
1398 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1399 Application::GetSettings().GetLanguageTag().getLanguageType())
1400 , m_aEditLoseFocusIdle("sfx2 CustomPropertiesWindow loseFocusIdle")
1401 , m_aBoxLoseFocusIdle("sfx2 CustomPropertiesWindow m_aBoxLoseFocusIdle")
1402 , m_rBody(rParent)
1403 , m_rHeaderAccName(rHeaderAccName)
1404 , m_rHeaderAccType(rHeaderAccType)
1405 , m_rHeaderAccValue(rHeaderAccValue)
1407 m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1408 m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1409 m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1410 m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1413 CustomPropertiesWindow::~CustomPropertiesWindow()
1415 m_aEditLoseFocusIdle.Stop();
1416 m_aBoxLoseFocusIdle.Stop();
1418 m_pCurrentLine = nullptr;
1421 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1423 auto nType = rBox.get_active_id().toInt32();
1424 m_xValueEdit->set_visible( (Custom_Type_Text == nType) || (Custom_Type_Number == nType) );
1425 m_xDateTimeBox->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1426 m_xDateField->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1427 m_xTimeField->set_visible( Custom_Type_Datetime == nType );
1428 m_xDurationBox->set_visible( Custom_Type_Duration == nType );
1429 m_xDurationField->set_visible( Custom_Type_Duration == nType );
1430 m_xYesNoButton->set_visible( Custom_Type_Boolean == nType );
1433 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1435 DoTypeHdl(rBox);
1438 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1440 StoreCustomProperties();
1442 auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1443 [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1444 if ( pFound != m_aCustomPropertiesLines.end() )
1446 sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1447 sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1448 m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1450 ReloadLinesContent();
1453 m_aRemovedHdl.Call(nullptr);
1456 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1458 m_pParent->Remove(this);
1461 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1463 m_pCurrentLine = pLine;
1464 m_aEditLoseFocusIdle.Start();
1467 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1469 if (!m_bTypeLostFocus)
1470 m_pParent->EditLoseFocus(this);
1471 else
1472 m_bTypeLostFocus = false;
1475 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1477 m_pCurrentLine = pLine;
1478 m_aBoxLoseFocusIdle.Start();
1481 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1483 m_pParent->BoxLoseFocus(this);
1486 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1488 ValidateLine( m_pCurrentLine, false );
1491 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1493 ValidateLine( m_pCurrentLine, true );
1496 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1498 bool bIsValid = true;
1499 pLine->m_bTypeLostFocus = false;
1500 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1501 OUString sValue = pLine->m_xValueEdit->get_text();
1502 if ( sValue.isEmpty() )
1503 return true;
1505 sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1506 if ( Custom_Type_Number == nType )
1507 // tdf#116214 Scientific format allows to use also standard numbers
1508 nIndex = const_cast< SvNumberFormatter& >(
1509 m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1510 else if ( Custom_Type_Date == nType )
1511 nIndex = const_cast< SvNumberFormatter& >(
1512 m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1514 if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1516 sal_uInt32 nTemp = nIndex;
1517 double fDummy = 0.0;
1518 bIsValid = const_cast< SvNumberFormatter& >(
1519 m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1520 if ( bIsValid && nTemp != nIndex )
1521 // sValue is a number but the format doesn't match the index
1522 bIsValid = false;
1525 return bIsValid;
1528 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1530 if (pLine && !IsLineValid(pLine))
1532 if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1533 pLine->m_bTypeLostFocus = true;
1534 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1535 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1536 if (xMessageBox->run() == RET_OK)
1537 pLine->m_xTypeBox->set_active_id(OUString::number(Custom_Type_Text));
1538 else
1539 pLine->m_xValueEdit->grab_focus();
1543 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1545 while (GetExistingLineCount() < nCount)
1547 CreateNewLine();
1551 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1553 m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1554 ReloadLinesContent();
1557 void CustomPropertiesWindow::CreateNewLine()
1559 CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1560 pNewLine->m_xNameBox->set_accessible_relation_labeled_by(&m_rHeaderAccName);
1561 pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1562 pNewLine->m_xTypeBox->set_accessible_relation_labeled_by(&m_rHeaderAccType);
1563 pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1564 pNewLine->m_xValueEdit->set_accessible_relation_labeled_by(&m_rHeaderAccValue);
1565 pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1567 m_aCustomPropertiesLines.emplace_back( pNewLine );
1569 // this breaks online's jsdialogbuilder
1570 if (!comphelper::LibreOfficeKit::isActive()){
1571 // for ui-testing. Distinguish the elements in the lines
1572 sal_uInt16 nSize = m_aCustomPropertiesLines.size();
1573 pNewLine->m_xNameBox->set_buildable_name(
1574 pNewLine->m_xNameBox->get_buildable_name() + OString::number(nSize));
1575 pNewLine->m_xTypeBox->set_buildable_name(
1576 pNewLine->m_xTypeBox->get_buildable_name() + OString::number(nSize));
1577 pNewLine->m_xValueEdit->set_buildable_name(
1578 pNewLine->m_xValueEdit->get_buildable_name() + OString::number(nSize));
1579 pNewLine->m_xRemoveButton->set_buildable_name(
1580 pNewLine->m_xRemoveButton->get_buildable_name() + OString::number(nSize));
1583 pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1586 bool CustomPropertiesWindow::AreAllLinesValid() const
1588 bool bRet = true;
1589 for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1591 if ( !IsLineValid( pLine.get() ) )
1593 bRet = false;
1594 break;
1598 return bRet;
1601 void CustomPropertiesWindow::ClearAllLines()
1603 for (auto& pLine : m_aCustomPropertiesLines)
1605 pLine->Clear();
1607 m_pCurrentLine = nullptr;
1608 m_aCustomProperties.clear();
1609 m_nScrollPos = 0;
1612 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1614 StoreCustomProperties();
1615 m_nScrollPos += nNewPos;
1616 ReloadLinesContent();
1619 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1621 StoreCustomProperties();
1623 Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1624 std::transform(
1625 m_aCustomProperties.begin(), m_aCustomProperties.end(), aPropertiesSeq.getArray(),
1626 [](const auto& el) { return comphelper::makePropertyValue(el->m_sName, el->m_aValue); });
1628 return aPropertiesSeq;
1631 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1632 : m_xTimeField(std::move(xTimeField))
1633 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1634 , m_isUTC(false)
1636 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1637 m_xFormatter->EnableEmptyField(false);
1640 tools::Time CustomPropertiesTimeField::get_value() const
1642 return m_xFormatter->GetTime();
1645 void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1647 m_xFormatter->SetTime(rTime);
1650 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1654 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1655 : m_xDateField(pDateField)
1657 DateTime aDateTime(DateTime::SYSTEM);
1658 m_xDateField->set_date(aDateTime);
1661 void CustomPropertiesDateField::set_visible(bool bVisible)
1663 m_xDateField->set_visible(bVisible);
1666 Date CustomPropertiesDateField::get_date() const
1668 return m_xDateField->get_date();
1671 void CustomPropertiesDateField::set_date(const Date& rDate)
1673 m_xDateField->set_date(rDate);
1676 CustomPropertiesDateField::~CustomPropertiesDateField()
1680 void CustomPropertiesWindow::StoreCustomProperties()
1682 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1684 for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1686 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1688 OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1689 if (!sPropertyName.isEmpty())
1691 m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1692 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1693 if (Custom_Type_Number == nType)
1695 double nValue = 0;
1696 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1697 bool bIsNum = m_aNumberFormatter.
1698 IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1699 if (bIsNum)
1700 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1702 else if (Custom_Type_Boolean == nType)
1704 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1705 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1707 else if (Custom_Type_Datetime == nType)
1709 Date aTmpDate = pLine->m_xDateField->get_date();
1710 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1711 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1712 aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1713 aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1714 pLine->m_xTimeField->m_isUTC);
1715 if (pLine->m_xDateField->m_TZ)
1717 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1718 aDateTime, *pLine->m_xDateField->m_TZ);
1720 else
1722 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1725 else if (Custom_Type_Date == nType)
1727 Date aTmpDate = pLine->m_xDateField->get_date();
1728 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1729 aTmpDate.GetYear());
1730 if (pLine->m_xDateField->m_TZ)
1732 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1733 aDate, *pLine->m_xDateField->m_TZ);
1735 else
1737 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1740 else if (Custom_Type_Duration == nType)
1742 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1744 else
1746 OUString sValue(pLine->m_xValueEdit->get_text());
1747 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1753 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1755 m_aCustomProperties = std::move(rProperties);
1756 ReloadLinesContent();
1759 void CustomPropertiesWindow::ReloadLinesContent()
1761 double nTmpValue = 0;
1762 bool bTmpValue = false;
1763 OUString sTmpValue;
1764 util::DateTime aTmpDateTime;
1765 util::Date aTmpDate;
1766 util::DateTimeWithTimezone aTmpDateTimeTZ;
1767 util::DateWithTimezone aTmpDateTZ;
1768 util::Duration aTmpDuration;
1769 SvtSysLocale aSysLocale;
1770 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1771 CustomProperties nType = Custom_Type_Unknown;
1772 OUString sValue;
1774 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1775 sal_uInt32 i = 0;
1777 for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1779 const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1780 const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1782 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1783 pLine->Clear();
1785 pLine->m_xNameBox->set_entry_text(rName);
1786 pLine->m_xLine->show();
1788 if (!rAny.hasValue())
1790 pLine->m_xValueEdit->set_text(OUString());
1792 else if (rAny >>= nTmpValue)
1794 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1795 m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex, sValue);
1796 pLine->m_xValueEdit->set_text(sValue);
1797 nType = Custom_Type_Number;
1799 else if (rAny >>= bTmpValue)
1801 sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1802 nType = Custom_Type_Boolean;
1804 else if (rAny >>= sTmpValue)
1806 pLine->m_xValueEdit->set_text(sTmpValue);
1807 nType = Custom_Type_Text;
1809 else if (rAny >>= aTmpDate)
1811 pLine->m_xDateField->set_date(Date(aTmpDate));
1812 nType = Custom_Type_Date;
1814 else if (rAny >>= aTmpDateTime)
1816 pLine->m_xDateField->set_date(Date(aTmpDateTime));
1817 pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1818 pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1819 nType = Custom_Type_Datetime;
1821 else if (rAny >>= aTmpDateTZ)
1823 pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1824 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1825 pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1826 nType = Custom_Type_Date;
1829 else if (rAny >>= aTmpDateTimeTZ)
1831 util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1832 pLine->m_xDateField->set_date(Date(rDT));
1833 pLine->m_xTimeField->set_value(tools::Time(rDT));
1834 pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1835 pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1836 nType = Custom_Type_Datetime;
1838 else if (rAny >>= aTmpDuration)
1840 nType = Custom_Type_Duration;
1841 pLine->m_xDurationField->SetDuration(aTmpDuration);
1844 if (Custom_Type_Boolean == nType)
1846 if (bTmpValue)
1847 pLine->m_xYesNoButton->CheckYes();
1848 else
1849 pLine->m_xYesNoButton->CheckNo();
1851 pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1853 pLine->DoTypeHdl(*pLine->m_xTypeBox);
1856 // tdf#132667 - grab focus on the last inserted property
1857 if (i > 0 && m_aCustomProperties[nDataModelPos + i - 1]->m_sName.isEmpty())
1859 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i - 1].get();
1860 pLine->m_xNameBox->grab_focus();
1863 while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1865 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1866 pLine->Hide();
1867 i++;
1871 CustomPropertiesControl::CustomPropertiesControl()
1872 : m_nThumbPos(0)
1876 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
1878 m_xBox = rBuilder.weld_widget("box");
1879 m_xBody = rBuilder.weld_container("properties");
1881 m_xName = rBuilder.weld_label("name");
1882 m_xType = rBuilder.weld_label("type");
1883 m_xValue = rBuilder.weld_label("value");
1884 m_xVertScroll = rBuilder.weld_scrolled_window("scroll", true);
1885 m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
1887 m_xBox->set_stack_background();
1888 m_xVertScroll->show();
1890 std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
1891 Size aLineSize(xNewLine->m_xLine->get_preferred_size());
1892 m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
1893 m_xBody->set_size_request(aLineSize.Width() + 6, -1);
1894 auto nHeight = aLineSize.Height() * 8;
1895 m_xVertScroll->set_size_request(-1, nHeight + 6);
1897 m_xPropertiesWin->SetHeight(nHeight);
1898 m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
1900 m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
1901 m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
1902 m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
1904 m_xBody->move(xNewLine->m_xLine.get(), nullptr);
1905 xNewLine.reset();
1907 m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
1909 m_xVertScroll->vadjustment_set_lower(0);
1910 m_xVertScroll->vadjustment_set_upper(0);
1911 m_xVertScroll->vadjustment_set_page_size(0xFFFF);
1913 Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
1914 m_xVertScroll->connect_vadjustment_changed(aScrollLink);
1916 ResizeHdl(Size(-1, nHeight));
1919 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
1921 int nHeight = rSize.Height() - 6;
1922 if (nHeight == m_xPropertiesWin->GetHeight())
1923 return;
1924 m_xPropertiesWin->SetHeight(nHeight);
1925 sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
1926 sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
1927 m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
1928 m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
1929 m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
1930 m_xPropertiesWin->ReloadLinesContent();
1933 CustomPropertiesControl::~CustomPropertiesControl()
1937 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
1939 sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
1940 int nThumbPos = rScrollBar.vadjustment_get_value();
1941 nOffset *= ( m_nThumbPos - nThumbPos );
1942 m_nThumbPos = nThumbPos;
1943 m_xPropertiesWin->DoScroll( nOffset );
1946 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
1948 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1949 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1950 if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
1952 m_xVertScroll->vadjustment_set_value(nLineCount - 1);
1953 ScrollHdl(*m_xVertScroll);
1957 void CustomPropertiesControl::AddLine( Any const & rAny )
1959 m_xPropertiesWin->AddLine( OUString(), rAny );
1960 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1961 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1962 if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
1964 m_xVertScroll->vadjustment_set_value(nLineCount + 1);
1965 ScrollHdl(*m_xVertScroll);
1969 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1971 m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
1972 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1973 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1976 // class SfxCustomPropertiesPage -----------------------------------------
1977 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
1978 : SfxTabPage(pPage, pController, "sfx/ui/custominfopage.ui", "CustomInfoPage", &rItemSet)
1979 , m_xPropertiesCtrl(new CustomPropertiesControl)
1980 , m_xAdd(m_xBuilder->weld_button("add"))
1982 m_xPropertiesCtrl->Init(*m_xBuilder);
1983 m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
1986 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
1988 m_xPropertiesCtrl.reset();
1991 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
1993 // tdf#115853: reload current lines before adding a brand new one
1994 // indeed the info are deleted by ClearCustomProperties
1995 // each time SfxDocumentInfoItem destructor is called
1996 SfxDocumentInfoItem pInfo;
1997 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1998 for ( const auto& rProperty : aPropertySeq )
2000 if ( !rProperty.Name.isEmpty() )
2002 pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
2006 Any aAny;
2007 m_xPropertiesCtrl->AddLine(aAny);
2010 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
2012 const SfxPoolItem* pItem = nullptr;
2013 SfxDocumentInfoItem* pInfo = nullptr;
2014 bool bMustDelete = false;
2016 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2018 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
2019 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2020 else
2022 bMustDelete = true;
2023 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
2027 if ( pInfo )
2029 // If it's a CMIS document, we can't save custom properties
2030 if ( pInfo->isCmisDocument( ) )
2032 if ( bMustDelete )
2033 delete pInfo;
2034 return false;
2037 pInfo->ClearCustomProperties();
2038 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2039 for ( const auto& rProperty : aPropertySeq )
2041 if ( !rProperty.Name.isEmpty() )
2042 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
2046 if (pInfo)
2048 rSet->Put(*pInfo);
2049 if ( bMustDelete )
2050 delete pInfo;
2052 return true;
2055 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
2057 m_xPropertiesCtrl->ClearAllLines();
2058 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2059 std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
2060 // tdf#123919 - sort custom document properties
2061 auto const sort = comphelper::string::NaturalStringSorter(
2062 comphelper::getProcessComponentContext(),
2063 Application::GetSettings().GetLanguageTag().getLocale());
2064 std::sort(aCustomProps.begin(), aCustomProps.end(),
2065 [&sort](const std::unique_ptr<CustomProperty>& rLHS,
2066 const std::unique_ptr<CustomProperty>& rRHS) {
2067 return sort.compare(rLHS->m_sName, rRHS->m_sName) < 0;
2069 m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
2072 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2074 DeactivateRC nRet = DeactivateRC::LeavePage;
2075 if ( !m_xPropertiesCtrl->AreAllLinesValid() )
2076 nRet = DeactivateRC::KeepPage;
2077 return nRet;
2080 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2082 return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
2085 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
2086 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2087 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2088 , m_xValueEdit(m_xBuilder->weld_entry("value"))
2090 m_xValueEdit->show();
2091 m_xValueEdit->set_text(aStr);
2094 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
2095 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2096 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2097 , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date")))
2098 , m_xTimeField(m_xBuilder->weld_formatted_spin_button("time"))
2099 , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
2101 m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
2102 m_xFormatter->EnableEmptyField(false);
2104 m_xDateField->show();
2105 m_xTimeField->show();
2106 m_xDateField->set_date(Date(aDateTime));
2107 m_xFormatter->SetTime(tools::Time(aDateTime));
2110 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
2111 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2112 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2113 , m_xYesButton(m_xBuilder->weld_radio_button("yes"))
2114 , m_xNoButton(m_xBuilder->weld_radio_button("no"))
2116 m_xYesButton->show();
2117 m_xNoButton->show();
2118 if (bValue)
2119 m_xYesButton->set_active(true);
2120 else
2121 m_xNoButton->set_active(true);
2124 // struct CmisPropertyLine ---------------------------------------------
2125 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2126 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
2127 , m_sType(CMIS_TYPE_STRING)
2128 , m_bUpdatable(false)
2129 , m_bRequired(false)
2130 , m_bMultiValued(false)
2131 , m_bOpenChoice(false)
2132 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
2133 , m_xName(m_xBuilder->weld_label("name"))
2134 , m_xType(m_xBuilder->weld_label("type"))
2136 m_xFrame->set_sensitive(true);
2139 CmisPropertyLine::~CmisPropertyLine( )
2143 // class CmisPropertiesWindow -----------------------------------------
2145 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2146 : m_xBox(std::move(xParent))
2147 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2148 Application::GetSettings().GetLanguageTag().getLanguageType())
2152 CmisPropertiesWindow::~CmisPropertiesWindow()
2156 void CmisPropertiesWindow::ClearAllLines()
2158 m_aCmisPropertiesLines.clear();
2161 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2162 const OUString& sType, const bool bUpdatable,
2163 const bool bRequired, const bool bMultiValued,
2164 const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2166 std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2168 pNewLine->m_sId = sId;
2169 pNewLine->m_sType = sType;
2170 pNewLine->m_bUpdatable = bUpdatable;
2171 pNewLine->m_bRequired = bRequired;
2172 pNewLine->m_bMultiValued = bMultiValued;
2173 pNewLine->m_bOpenChoice = bOpenChoice;
2175 if ( sType == CMIS_TYPE_INTEGER )
2177 Sequence< sal_Int64 > seqValue;
2178 rAny >>= seqValue;
2179 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2180 for ( const auto& rValue : std::as_const(seqValue) )
2182 OUString sValue;
2183 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2184 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2185 pValue->m_xValueEdit->set_editable(bUpdatable);
2186 pNewLine->m_aValues.push_back( std::move(pValue) );
2189 else if ( sType == CMIS_TYPE_DECIMAL )
2191 Sequence< double > seqValue;
2192 rAny >>= seqValue;
2193 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2194 for ( const auto& rValue : std::as_const(seqValue) )
2196 OUString sValue;
2197 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2198 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2199 pValue->m_xValueEdit->set_editable(bUpdatable);
2200 pNewLine->m_aValues.push_back( std::move(pValue) );
2204 else if ( sType == CMIS_TYPE_BOOL )
2206 Sequence<sal_Bool> seqValue;
2207 rAny >>= seqValue;
2208 for ( const auto& rValue : std::as_const(seqValue) )
2210 std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2211 pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2212 pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2213 pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2216 else if ( sType == CMIS_TYPE_STRING )
2218 Sequence< OUString > seqValue;
2219 rAny >>= seqValue;
2220 for ( const auto& rValue : std::as_const(seqValue) )
2222 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2223 pValue->m_xValueEdit->set_editable(bUpdatable);
2224 pNewLine->m_aValues.push_back( std::move(pValue) );
2227 else if ( sType == CMIS_TYPE_DATETIME )
2229 Sequence< util::DateTime > seqValue;
2230 rAny >>= seqValue;
2231 for ( const auto& rValue : std::as_const(seqValue) )
2233 std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2234 pDateTime->m_xDateField->set_sensitive(bUpdatable);
2235 pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2236 pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2239 pNewLine->m_xName->set_label( sName );
2240 pNewLine->m_xName->show();
2241 pNewLine->m_xType->set_label( sType );
2242 pNewLine->m_xType->show();
2244 m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2247 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2249 Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2250 auto aPropertiesSeqRange = asNonConstRange(aPropertiesSeq);
2251 sal_Int32 i = 0;
2252 for ( auto& rxLine : m_aCmisPropertiesLines )
2254 CmisPropertyLine* pLine = rxLine.get();
2256 aPropertiesSeqRange[i].Id = pLine->m_sId;
2257 aPropertiesSeqRange[i].Type = pLine->m_sType;
2258 aPropertiesSeqRange[i].Updatable = pLine->m_bUpdatable;
2259 aPropertiesSeqRange[i].Required = pLine->m_bRequired;
2260 aPropertiesSeqRange[i].OpenChoice = pLine->m_bOpenChoice;
2261 aPropertiesSeqRange[i].MultiValued = pLine->m_bMultiValued;
2263 OUString sPropertyName = pLine->m_xName->get_label();
2264 if ( !sPropertyName.isEmpty() )
2266 aPropertiesSeqRange[i].Name = sPropertyName;
2267 OUString sType = pLine->m_xType->get_label();
2268 if ( CMIS_TYPE_DECIMAL == sType )
2270 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2271 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2272 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2273 auto seqValueRange = asNonConstRange(seqValue);
2274 sal_Int32 k = 0;
2275 for ( const auto& rxValue : pLine->m_aValues )
2277 double dValue = 0.0;
2278 OUString sValue( rxValue->m_xValueEdit->get_text() );
2279 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2280 IsNumberFormat( sValue, nIndex, dValue );
2281 if ( bIsNum )
2282 seqValueRange[k] = dValue;
2283 ++k;
2285 aPropertiesSeqRange[i].Value <<= seqValue;
2287 else if ( CMIS_TYPE_INTEGER == sType )
2289 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2290 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2291 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2292 auto seqValueRange = asNonConstRange(seqValue);
2293 sal_Int32 k = 0;
2294 for ( const auto& rxValue : pLine->m_aValues )
2296 double dValue = 0;
2297 OUString sValue( rxValue->m_xValueEdit->get_text() );
2298 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2299 IsNumberFormat( sValue, nIndex, dValue );
2300 if ( bIsNum )
2301 seqValueRange[k] = static_cast<sal_Int64>(dValue);
2302 ++k;
2304 aPropertiesSeqRange[i].Value <<= seqValue;
2306 else if ( CMIS_TYPE_BOOL == sType )
2308 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2309 sal_Bool* pseqValue = seqValue.getArray();
2310 sal_Int32 k = 0;
2311 for ( const auto& rxYesNo : pLine->m_aYesNos )
2313 bool bValue = rxYesNo->m_xYesButton->get_active();
2314 pseqValue[k] = bValue;
2315 ++k;
2317 aPropertiesSeqRange[i].Value <<= seqValue;
2320 else if ( CMIS_TYPE_DATETIME == sType )
2322 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2323 auto seqValueRange = asNonConstRange(seqValue);
2324 sal_Int32 k = 0;
2325 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2327 Date aTmpDate = rxDateTime->m_xDateField->get_date();
2328 tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2329 util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2330 aTmpTime.GetMin(), aTmpTime.GetHour(),
2331 aTmpDate.GetDay(), aTmpDate.GetMonth(),
2332 aTmpDate.GetYear(), true );
2333 seqValueRange[k] = aDateTime;
2334 ++k;
2336 aPropertiesSeqRange[i].Value <<= seqValue;
2338 else
2340 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2341 auto seqValueRange = asNonConstRange(seqValue);
2342 sal_Int32 k = 0;
2343 for ( const auto& rxValue : pLine->m_aValues )
2345 OUString sValue( rxValue->m_xValueEdit->get_text() );
2346 seqValueRange[k] = sValue;
2347 ++k;
2349 aPropertiesSeqRange[i].Value <<= seqValue;
2352 ++i;
2355 return aPropertiesSeq;
2358 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2359 : m_aPropertiesWin(rBuilder.weld_container("CmisWindow"))
2360 , m_xScrolledWindow(rBuilder.weld_scrolled_window("CmisScroll"))
2362 // set height to something small and force it to take the size
2363 // dictated by the other pages
2364 m_xScrolledWindow->set_size_request(-1, 42);
2367 void CmisPropertiesControl::ClearAllLines()
2369 m_aPropertiesWin.ClearAllLines();
2372 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2373 const OUString& sType, const bool bUpdatable,
2374 const bool bRequired, const bool bMultiValued,
2375 const bool bOpenChoice, Any& aChoices, Any const & rAny
2378 m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2379 bOpenChoice, aChoices, rAny );
2382 // class SfxCmisPropertiesPage -----------------------------------------
2383 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2384 : SfxTabPage(pPage, pController, "sfx/ui/cmisinfopage.ui", "CmisInfoPage", &rItemSet)
2385 , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2389 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2391 m_xPropertiesCtrl.reset();
2394 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2396 const SfxPoolItem* pItem = nullptr;
2397 SfxDocumentInfoItem* pInfo = nullptr;
2398 bool bMustDelete = false;
2400 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2402 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
2403 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2404 else
2406 bMustDelete = true;
2407 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
2411 sal_Int32 modifiedNum = 0;
2412 if ( pInfo )
2414 Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2415 Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2417 std::vector< document::CmisProperty > changedProps;
2418 for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2420 if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2422 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2424 Sequence< util::DateTime > oldValue;
2425 aOldProps[i].Value >>= oldValue;
2426 // We only edit hours and minutes
2427 // don't compare NanoSeconds and Seconds
2428 for ( auto& rDateTime : asNonConstRange(oldValue) )
2430 rDateTime.NanoSeconds = 0;
2431 rDateTime.Seconds = 0;
2433 Sequence< util::DateTime > newValue;
2434 aNewProps[i].Value >>= newValue;
2435 if ( oldValue != newValue )
2437 modifiedNum++;
2438 changedProps.push_back( aNewProps[i] );
2441 else if ( aOldProps[i].Value != aNewProps[i].Value )
2443 modifiedNum++;
2444 changedProps.push_back( aNewProps[i] );
2448 Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2449 pInfo->SetCmisProperties( aModifiedProps );
2450 rSet->Put( *pInfo );
2451 if ( bMustDelete )
2452 delete pInfo;
2455 return modifiedNum;
2458 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2460 m_xPropertiesCtrl->ClearAllLines();
2461 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2462 uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2463 for ( auto& rCmisProp : asNonConstRange(aCmisProps) )
2465 m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2466 rCmisProp.Name,
2467 rCmisProp.Type,
2468 rCmisProp.Updatable,
2469 rCmisProp.Required,
2470 rCmisProp.MultiValued,
2471 rCmisProp.OpenChoice,
2472 rCmisProp.Choices,
2473 rCmisProp.Value);
2477 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2479 return DeactivateRC::LeavePage;
2482 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2484 return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2487 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */