1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20 #include <svl/eitem.hxx>
21 #include <svl/urihelper.hxx>
22 #include <tools/datetime.hxx>
23 #include <tools/debug.hxx>
24 #include <tools/urlobj.hxx>
25 #include <vcl/mnemonic.hxx>
26 #include <vcl/svapp.hxx>
27 #include <vcl/weld.hxx>
28 #include <unotools/datetime.hxx>
29 #include <unotools/localedatawrapper.hxx>
30 #include <unotools/cmdoptions.hxx>
31 #include <comphelper/processfactory.hxx>
32 #include <comphelper/xmlsechelper.hxx>
33 #include <unotools/useroptions.hxx>
34 #include <svtools/controldims.hxx>
35 #include <svtools/imagemgr.hxx>
36 #include <toolkit/helper/vclunohelper.hxx>
37 #include <sal/log.hxx>
38 #include <osl/diagnose.h>
39
40 #include <memory>
41
42 #include <comphelper/sequence.hxx>
43 #include <comphelper/string.hxx>
44 #include <com/sun/star/security/DocumentSignatureInformation.hpp>
45 #include <com/sun/star/security/DocumentDigitalSignatures.hpp>
46 #include <unotools/syslocale.hxx>
47 #include <rtl/math.hxx>
48 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp>
49 #include <com/sun/star/beans/PropertyAttribute.hpp>
50 #include <com/sun/star/beans/XPropertyContainer.hpp>
51 #include <com/sun/star/beans/XPropertySet.hpp>
52 #include <com/sun/star/util/DateTime.hpp>
53 #include <com/sun/star/util/Date.hpp>
54 #include <com/sun/star/util/DateTimeWithTimezone.hpp>
55 #include <com/sun/star/util/DateWithTimezone.hpp>
56 #include <com/sun/star/util/Duration.hpp>
57 #include <com/sun/star/document/XDocumentProperties.hpp>
58 #include <com/sun/star/document/CmisProperty.hpp>
59
60 #include <vcl/timer.hxx>
61 #include <vcl/settings.hxx>
62 #include <sfx2/securitypage.hxx>
63 #include <sfx2/sfxresid.hxx>
64 #include <sfx2/frame.hxx>
65 #include <sfx2/viewfrm.hxx>
66 #include <sfx2/request.hxx>
67 #include <sfx2/passwd.hxx>
68 #include <sfx2/filedlghelper.hxx>
69 #include <sfx2/dinfdlg.hxx>
70 #include <sfx2/sfxsids.hrc>
71 #include <helper.hxx>
72 #include <sfx2/objsh.hxx>
73 #include <sfx2/docfile.hxx>
74
75 #include <documentfontsdialog.hxx>
76 #include <dinfdlg.hrc>
77 #include <sfx2/strings.hrc>
78 #include <strings.hxx>
79 #include <bitmaps.hlst>
80 #include <vcl/help.hxx>
81 #include <tools/diagnose_ex.h>
82
83 #include <algorithm>
84
85 using namespace ::com::sun::star;
86 using namespace ::com::sun::star::lang;
87 using namespace ::com::sun::star::ui::dialogs;
88 using namespace ::com::sun::star::uno;
89
90 struct CustomProperty
91 {
92 OUString m_sName;
93 css::uno::Any m_aValue;
94
CustomPropertyCustomProperty95 CustomProperty( const OUString& sName, const css::uno::Any& rValue ) :
96 m_sName( sName ), m_aValue( rValue ) {}
97 };
98
CreateDefault()99 SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
100
101 namespace {
102
CreateSizeText(sal_Int64 nSize)103 OUString CreateSizeText( sal_Int64 nSize )
104 {
105 OUString aUnitStr = " " + SfxResId(STR_BYTES);
106 sal_Int64 nSize1 = nSize;
107 sal_Int64 nSize2 = nSize1;
108 sal_Int64 nMega = 1024 * 1024;
109 sal_Int64 nGiga = nMega * 1024;
110 double fSize = nSize;
111 int nDec = 0;
112
113 if ( nSize1 >= 10000 && nSize1 < nMega )
114 {
115 nSize1 /= 1024;
116 aUnitStr = " " + SfxResId(STR_KB);
117 fSize /= 1024;
118 nDec = 0;
119 }
120 else if ( nSize1 >= nMega && nSize1 < nGiga )
121 {
122 nSize1 /= nMega;
123 aUnitStr = " " + SfxResId(STR_MB);
124 fSize /= nMega;
125 nDec = 2;
126 }
127 else if ( nSize1 >= nGiga )
128 {
129 nSize1 /= nGiga;
130 aUnitStr = " " + SfxResId(STR_GB);
131 fSize /= nGiga;
132 nDec = 3;
133 }
134 const SvtSysLocale aSysLocale;
135 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
136 OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
137 if ( nSize1 < nSize2 )
138 {
139 aSizeStr = ::rtl::math::doubleToUString( fSize,
140 rtl_math_StringFormat_F, nDec,
141 rLocaleWrapper.getNumDecimalSep()[0] )
142 + aUnitStr
143 + " ("
144 + rLocaleWrapper.getNum( nSize2, 0 )
145 + " "
146 + SfxResId(STR_BYTES)
147 + ")";
148 }
149 return aSizeStr;
150 }
151
ConvertDateTime_Impl(const OUString & rName,const util::DateTime & uDT,const LocaleDataWrapper & rWrapper)152 OUString ConvertDateTime_Impl( const OUString& rName,
153 const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
154 {
155 Date aD(uDT);
156 tools::Time aT(uDT);
157 const OUString aDelim( ", " );
158 OUString aStr = rWrapper.getDate( aD )
159 + aDelim
160 + rWrapper.getTime( aT );
161 OUString aAuthor = comphelper::string::stripStart(rName, ' ');
162 if (!aAuthor.isEmpty())
163 {
164 aStr += aDelim + aAuthor;
165 }
166 return aStr;
167 }
168
169 }
170
171
SfxDocumentInfoItem()172 SfxDocumentInfoItem::SfxDocumentInfoItem()
173 : SfxStringItem()
174 , m_AutoloadDelay(0)
175 , m_AutoloadURL()
176 , m_isAutoloadEnabled(false)
177 , m_DefaultTarget()
178 , m_TemplateName()
179 , m_Author()
180 , m_CreationDate()
181 , m_ModifiedBy()
182 , m_ModificationDate()
183 , m_PrintedBy()
184 , m_PrintDate()
185 , m_EditingCycles(0)
186 , m_EditingDuration(0)
187 , m_Description()
188 , m_Keywords()
189 , m_Subject()
190 , m_Title()
191 , m_bHasTemplate( true )
192 , m_bDeleteUserData( false )
193 , m_bUseUserData( true )
194 , m_bUseThumbnailSave( true )
195 {
196 }
197
SfxDocumentInfoItem(const OUString & rFile,const uno::Reference<document::XDocumentProperties> & i_xDocProps,const uno::Sequence<document::CmisProperty> & i_cmisProps,bool bIs,bool _bIs)198 SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
199 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
200 const uno::Sequence<document::CmisProperty>& i_cmisProps,
201 bool bIs, bool _bIs )
202 : SfxStringItem( SID_DOCINFO, rFile )
203 , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
204 , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
205 , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
206 , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
207 , m_TemplateName( i_xDocProps->getTemplateName() )
208 , m_Author( i_xDocProps->getAuthor() )
209 , m_CreationDate( i_xDocProps->getCreationDate() )
210 , m_ModifiedBy( i_xDocProps->getModifiedBy() )
211 , m_ModificationDate( i_xDocProps->getModificationDate() )
212 , m_PrintedBy( i_xDocProps->getPrintedBy() )
213 , m_PrintDate( i_xDocProps->getPrintDate() )
214 , m_EditingCycles( i_xDocProps->getEditingCycles() )
215 , m_EditingDuration( i_xDocProps->getEditingDuration() )
216 , m_Description( i_xDocProps->getDescription() )
217 , m_Keywords( ::comphelper::string::convertCommaSeparated(
218 i_xDocProps->getKeywords()) )
219 , m_Subject( i_xDocProps->getSubject() )
220 , m_Title( i_xDocProps->getTitle() )
221 , m_bHasTemplate( true )
222 , m_bDeleteUserData( false )
223 , m_bUseUserData( bIs )
224 , m_bUseThumbnailSave( _bIs )
225 {
226 try
227 {
228 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
229 if ( xContainer.is() )
230 {
231 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
232 const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
233 for ( const beans::Property& rProp : lProps )
234 {
235 // "fix" property? => not a custom property => ignore it!
236 if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
237 {
238 SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
239 continue;
240 }
241
242 uno::Any aValue = xSet->getPropertyValue(rProp.Name);
243 std::unique_ptr<CustomProperty> pProp(new CustomProperty( rProp.Name, aValue ));
244 m_aCustomProperties.push_back( std::move(pProp) );
245 }
246 }
247
248 // get CMIS properties
249 m_aCmisProperties = i_cmisProps;
250 }
251 catch ( Exception& ) {}
252 }
253
254
SfxDocumentInfoItem(const SfxDocumentInfoItem & rItem)255 SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
256 : SfxStringItem( rItem )
257 , m_AutoloadDelay( rItem.getAutoloadDelay() )
258 , m_AutoloadURL( rItem.getAutoloadURL() )
259 , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
260 , m_DefaultTarget( rItem.getDefaultTarget() )
261 , m_TemplateName( rItem.getTemplateName() )
262 , m_Author( rItem.getAuthor() )
263 , m_CreationDate( rItem.getCreationDate() )
264 , m_ModifiedBy( rItem.getModifiedBy() )
265 , m_ModificationDate( rItem.getModificationDate() )
266 , m_PrintedBy( rItem.getPrintedBy() )
267 , m_PrintDate( rItem.getPrintDate() )
268 , m_EditingCycles( rItem.getEditingCycles() )
269 , m_EditingDuration( rItem.getEditingDuration() )
270 , m_Description( rItem.getDescription() )
271 , m_Keywords( rItem.getKeywords() )
272 , m_Subject( rItem.getSubject() )
273 , m_Title( rItem.getTitle() )
274 , m_bHasTemplate( rItem.m_bHasTemplate )
275 , m_bDeleteUserData( rItem.m_bDeleteUserData )
276 , m_bUseUserData( rItem.m_bUseUserData )
277 , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
278 {
279 for (auto const & pOtherProp : rItem.m_aCustomProperties)
280 {
281 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
282 pOtherProp->m_aValue ));
283 m_aCustomProperties.push_back( std::move(pProp) );
284 }
285
286 m_aCmisProperties = rItem.m_aCmisProperties;
287 }
288
289
~SfxDocumentInfoItem()290 SfxDocumentInfoItem::~SfxDocumentInfoItem()
291 {
292 ClearCustomProperties();
293 }
294
295
Clone(SfxItemPool *) const296 SfxPoolItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
297 {
298 return new SfxDocumentInfoItem( *this );
299 }
300
301
operator ==(const SfxPoolItem & rItem) const302 bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
303 {
304 if (!SfxStringItem::operator==(rItem))
305 return false;
306 const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
307
308 return
309 m_AutoloadDelay == rInfoItem.m_AutoloadDelay &&
310 m_AutoloadURL == rInfoItem.m_AutoloadURL &&
311 m_isAutoloadEnabled == rInfoItem.m_isAutoloadEnabled &&
312 m_DefaultTarget == rInfoItem.m_DefaultTarget &&
313 m_Author == rInfoItem.m_Author &&
314 m_CreationDate == rInfoItem.m_CreationDate &&
315 m_ModifiedBy == rInfoItem.m_ModifiedBy &&
316 m_ModificationDate == rInfoItem.m_ModificationDate &&
317 m_PrintedBy == rInfoItem.m_PrintedBy &&
318 m_PrintDate == rInfoItem.m_PrintDate &&
319 m_EditingCycles == rInfoItem.m_EditingCycles &&
320 m_EditingDuration == rInfoItem.m_EditingDuration &&
321 m_Description == rInfoItem.m_Description &&
322 m_Keywords == rInfoItem.m_Keywords &&
323 m_Subject == rInfoItem.m_Subject &&
324 m_Title == rInfoItem.m_Title &&
325 m_aCustomProperties.size() == rInfoItem.m_aCustomProperties.size() &&
326 std::equal(m_aCustomProperties.begin(), m_aCustomProperties.end(),
327 rInfoItem.m_aCustomProperties.begin()) &&
328 m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
329 }
330
331
resetUserData(const OUString & i_rAuthor)332 void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
333 {
334 setAuthor(i_rAuthor);
335 DateTime now( DateTime::SYSTEM );
336 m_CreationDate = now.GetUNODateTime();
337 setModifiedBy(OUString());
338 setPrintedBy(OUString());
339 m_ModificationDate = util::DateTime();
340 m_PrintDate = util::DateTime();
341 setEditingDuration(0);
342 setEditingCycles(1);
343 }
344
345
UpdateDocumentInfo(const uno::Reference<document::XDocumentProperties> & i_xDocProps,bool i_bDoNotUpdateUserDefined) const346 void SfxDocumentInfoItem::UpdateDocumentInfo(
347 const uno::Reference<document::XDocumentProperties>& i_xDocProps,
348 bool i_bDoNotUpdateUserDefined) const
349 {
350 if (isAutoloadEnabled()) {
351 i_xDocProps->setAutoloadSecs(getAutoloadDelay());
352 i_xDocProps->setAutoloadURL(getAutoloadURL());
353 } else {
354 i_xDocProps->setAutoloadSecs(0);
355 i_xDocProps->setAutoloadURL(OUString());
356 }
357 i_xDocProps->setDefaultTarget(getDefaultTarget());
358 i_xDocProps->setAuthor(getAuthor());
359 i_xDocProps->setCreationDate(getCreationDate());
360 i_xDocProps->setModifiedBy(getModifiedBy());
361 i_xDocProps->setModificationDate(getModificationDate());
362 i_xDocProps->setPrintedBy(getPrintedBy());
363 i_xDocProps->setPrintDate(getPrintDate());
364 i_xDocProps->setEditingCycles(getEditingCycles());
365 i_xDocProps->setEditingDuration(getEditingDuration());
366 i_xDocProps->setDescription(getDescription());
367 i_xDocProps->setKeywords(
368 ::comphelper::string::convertCommaSeparated(getKeywords()));
369 i_xDocProps->setSubject(getSubject());
370 i_xDocProps->setTitle(getTitle());
371
372 // this is necessary in case of replaying a recorded macro:
373 // in this case, the macro may contain the 4 old user-defined DocumentInfo
374 // fields, but not any of the DocumentInfo properties;
375 // as a consequence, most of the UserDefined properties of the
376 // DocumentProperties would be summarily deleted here, which does not
377 // seem like a good idea.
378 if (i_bDoNotUpdateUserDefined)
379 return;
380
381 try
382 {
383 Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
384 Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
385 Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
386 const Sequence< beans::Property > lProps = xSetInfo->getProperties();
387 for ( const beans::Property& rProp : lProps )
388 {
389 if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
390 {
391 xContainer->removeProperty( rProp.Name );
392 }
393 }
394
395 for (auto const & pProp : m_aCustomProperties)
396 {
397 try
398 {
399 xContainer->addProperty( pProp->m_sName,
400 beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
401 }
402 catch ( Exception const & )
403 {
404 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
405 }
406 }
407 }
408 catch ( Exception const & )
409 {
410 TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
411 }
412 }
413
414
SetDeleteUserData(bool bSet)415 void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
416 {
417 m_bDeleteUserData = bSet;
418 }
419
420
SetUseUserData(bool bSet)421 void SfxDocumentInfoItem::SetUseUserData( bool bSet )
422 {
423 m_bUseUserData = bSet;
424 }
425
SetUseThumbnailSave(bool bSet)426 void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
427 {
428 m_bUseThumbnailSave = bSet;
429 }
430
GetCustomProperties() const431 std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
432 {
433 std::vector< std::unique_ptr<CustomProperty> > aRet;
434 for (auto const & pOtherProp : m_aCustomProperties)
435 {
436 std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
437 pOtherProp->m_aValue ));
438 aRet.push_back( std::move(pProp) );
439 }
440
441 return aRet;
442 }
443
ClearCustomProperties()444 void SfxDocumentInfoItem::ClearCustomProperties()
445 {
446 m_aCustomProperties.clear();
447 }
448
AddCustomProperty(const OUString & sName,const Any & rValue)449 void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
450 {
451 std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
452 m_aCustomProperties.push_back( std::move(pProp) );
453 }
454
455
SetCmisProperties(const Sequence<document::CmisProperty> & cmisProps)456 void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
457 {
458 m_aCmisProperties = cmisProps;
459 }
460
QueryValue(Any & rVal,sal_uInt8 nMemberId) const461 bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
462 {
463 OUString aValue;
464 sal_Int32 nValue = 0;
465 bool bValue = false;
466 bool bIsInt = false;
467 bool bIsString = false;
468 nMemberId &= ~CONVERT_TWIPS;
469 switch ( nMemberId )
470 {
471 case MID_DOCINFO_USEUSERDATA:
472 bValue = IsUseUserData();
473 break;
474 case MID_DOCINFO_USETHUMBNAILSAVE:
475 bValue = IsUseThumbnailSave();
476 break;
477 case MID_DOCINFO_DELETEUSERDATA:
478 bValue = IsDeleteUserData();
479 break;
480 case MID_DOCINFO_AUTOLOADENABLED:
481 bValue = isAutoloadEnabled();
482 break;
483 case MID_DOCINFO_AUTOLOADSECS:
484 bIsInt = true;
485 nValue = getAutoloadDelay();
486 break;
487 case MID_DOCINFO_AUTOLOADURL:
488 bIsString = true;
489 aValue = getAutoloadURL();
490 break;
491 case MID_DOCINFO_DEFAULTTARGET:
492 bIsString = true;
493 aValue = getDefaultTarget();
494 break;
495 case MID_DOCINFO_DESCRIPTION:
496 bIsString = true;
497 aValue = getDescription();
498 break;
499 case MID_DOCINFO_KEYWORDS:
500 bIsString = true;
501 aValue = getKeywords();
502 break;
503 case MID_DOCINFO_SUBJECT:
504 bIsString = true;
505 aValue = getSubject();
506 break;
507 case MID_DOCINFO_TITLE:
508 bIsString = true;
509 aValue = getTitle();
510 break;
511 default:
512 OSL_FAIL("Wrong MemberId!");
513 return false;
514 }
515
516 if ( bIsString )
517 rVal <<= aValue;
518 else if ( bIsInt )
519 rVal <<= nValue;
520 else
521 rVal <<= bValue;
522 return true;
523 }
524
PutValue(const Any & rVal,sal_uInt8 nMemberId)525 bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
526 {
527 OUString aValue;
528 sal_Int32 nValue=0;
529 bool bValue = false;
530 bool bRet = false;
531 nMemberId &= ~CONVERT_TWIPS;
532 switch ( nMemberId )
533 {
534 case MID_DOCINFO_USEUSERDATA:
535 bRet = (rVal >>= bValue);
536 if ( bRet )
537 SetUseUserData( bValue );
538 break;
539 case MID_DOCINFO_USETHUMBNAILSAVE:
540 bRet = (rVal >>=bValue);
541 if ( bRet )
542 SetUseThumbnailSave( bValue );
543 break;
544 case MID_DOCINFO_DELETEUSERDATA:
545 // QUESTION: deleting user data was done here; seems to be superfluous!
546 bRet = (rVal >>= bValue);
547 if ( bRet )
548 SetDeleteUserData( bValue );
549 break;
550 case MID_DOCINFO_AUTOLOADENABLED:
551 bRet = (rVal >>= bValue);
552 if ( bRet )
553 setAutoloadEnabled(bValue);
554 break;
555 case MID_DOCINFO_AUTOLOADSECS:
556 bRet = (rVal >>= nValue);
557 if ( bRet )
558 setAutoloadDelay(nValue);
559 break;
560 case MID_DOCINFO_AUTOLOADURL:
561 bRet = (rVal >>= aValue);
562 if ( bRet )
563 setAutoloadURL(aValue);
564 break;
565 case MID_DOCINFO_DEFAULTTARGET:
566 bRet = (rVal >>= aValue);
567 if ( bRet )
568 setDefaultTarget(aValue);
569 break;
570 case MID_DOCINFO_DESCRIPTION:
571 bRet = (rVal >>= aValue);
572 if ( bRet )
573 setDescription(aValue);
574 break;
575 case MID_DOCINFO_KEYWORDS:
576 bRet = (rVal >>= aValue);
577 if ( bRet )
578 setKeywords(aValue);
579 break;
580 case MID_DOCINFO_SUBJECT:
581 bRet = (rVal >>= aValue);
582 if ( bRet )
583 setSubject(aValue);
584 break;
585 case MID_DOCINFO_TITLE:
586 bRet = (rVal >>= aValue);
587 if ( bRet )
588 setTitle(aValue);
589 break;
590 default:
591 OSL_FAIL("Wrong MemberId!");
592 return false;
593 }
594
595 return bRet;
596 }
597
SfxDocumentDescPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)598 SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
599 : SfxTabPage(pPage, pController, "sfx/ui/descriptioninfopage.ui", "DescriptionInfoPage", &rItemSet)
600 , m_pInfoItem(nullptr)
601 , m_xTitleEd(m_xBuilder->weld_entry("title"))
602 , m_xThemaEd(m_xBuilder->weld_entry("subject"))
603 , m_xKeywordsEd(m_xBuilder->weld_entry("keywords"))
604 , m_xCommentEd(m_xBuilder->weld_text_view("comments"))
605 {
606 m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
607 m_xCommentEd->get_height_rows(16));
608 }
609
~SfxDocumentDescPage()610 SfxDocumentDescPage::~SfxDocumentDescPage()
611 {
612 }
613
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)614 std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
615 {
616 return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
617 }
618
FillItemSet(SfxItemSet * rSet)619 bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
620 {
621 // Test whether a change is present
622 const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
623 const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
624 const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
625 const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
626 if ( !( bTitleMod || bThemeMod || bKeywordsMod || bCommentMod ) )
627 {
628 return false;
629 }
630
631 // Generating the output data
632 const SfxPoolItem* pItem = nullptr;
633 SfxDocumentInfoItem* pInfo = nullptr;
634 const SfxItemSet* pExSet = GetDialogExampleSet();
635
636 if ( pExSet && SfxItemState::SET != pExSet->GetItemState( SID_DOCINFO, true, &pItem ) )
637 pInfo = m_pInfoItem;
638 else if ( pItem )
639 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem *>(pItem) );
640
641 if ( !pInfo )
642 {
643 SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
644 return false;
645 }
646
647 if ( bTitleMod )
648 {
649 pInfo->setTitle( m_xTitleEd->get_text() );
650 }
651 if ( bThemeMod )
652 {
653 pInfo->setSubject( m_xThemaEd->get_text() );
654 }
655 if ( bKeywordsMod )
656 {
657 pInfo->setKeywords( m_xKeywordsEd->get_text() );
658 }
659 if ( bCommentMod )
660 {
661 pInfo->setDescription( m_xCommentEd->get_text() );
662 }
663 rSet->Put( *pInfo );
664 if ( pInfo != m_pInfoItem )
665 {
666 delete pInfo;
667 }
668
669 return true;
670 }
671
Reset(const SfxItemSet * rSet)672 void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
673 {
674 m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
675
676 m_xTitleEd->set_text(m_pInfoItem->getTitle());
677 m_xThemaEd->set_text(m_pInfoItem->getSubject());
678 m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
679 m_xCommentEd->set_text(m_pInfoItem->getDescription());
680
681 m_xTitleEd->save_value();
682 m_xThemaEd->save_value();
683 m_xKeywordsEd->save_value();
684 m_xCommentEd->save_value();
685
686 const SfxBoolItem* pROItem = SfxItemSet::GetItem<SfxBoolItem>(rSet, SID_DOC_READONLY, false);
687 if (pROItem && pROItem->GetValue())
688 {
689 m_xTitleEd->set_editable(false);
690 m_xThemaEd->set_editable(false);
691 m_xKeywordsEd->set_editable(false);
692 m_xCommentEd->set_editable(false);
693 }
694 }
695
SfxDocumentPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)696 SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
697 : SfxTabPage(pPage, pController, "sfx/ui/documentinfopage.ui", "DocumentInfoPage", &rItemSet)
698 , bEnableUseUserData( false )
699 , bHandleDelete( false )
700 , m_xBmp(m_xBuilder->weld_image("icon"))
701 , m_xNameED(m_xBuilder->weld_label("nameed"))
702 , m_xChangePassBtn(m_xBuilder->weld_button("changepass"))
703 , m_xShowTypeFT(m_xBuilder->weld_label("showtype"))
704 , m_xFileValEd(m_xBuilder->weld_label("showlocation"))
705 , m_xShowSizeFT(m_xBuilder->weld_label("showsize"))
706 , m_xCreateValFt(m_xBuilder->weld_label("showcreate"))
707 , m_xChangeValFt(m_xBuilder->weld_label("showmodify"))
708 , m_xSignedValFt(m_xBuilder->weld_label("showsigned"))
709 , m_xSignatureBtn(m_xBuilder->weld_button("signature"))
710 , m_xPrintValFt(m_xBuilder->weld_label("showprint"))
711 , m_xTimeLogValFt(m_xBuilder->weld_label("showedittime"))
712 , m_xDocNoValFt(m_xBuilder->weld_label("showrevision"))
713 , m_xUseUserDataCB(m_xBuilder->weld_check_button("userdatacb"))
714 , m_xDeleteBtn(m_xBuilder->weld_button("reset"))
715 , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button("thumbnailsavecb"))
716 , m_xTemplFt(m_xBuilder->weld_label("templateft"))
717 , m_xTemplValFt(m_xBuilder->weld_label("showtemplate"))
718 {
719 m_aUnknownSize = m_xShowSizeFT->get_label();
720 m_xShowSizeFT->set_label(OUString());
721
722 m_aMultiSignedStr = m_xSignedValFt->get_label();
723 m_xSignedValFt->set_label(OUString());
724
725 ImplUpdateSignatures();
726 ImplCheckPasswordState();
727 m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
728 m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
729 m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
730
731 // [i96288] Check if the document signature command is enabled
732 // on the main list enable/disable the pushbutton accordingly
733 SvtCommandOptions aCmdOptions;
734 if ( aCmdOptions.Lookup( SvtCommandOptions::CMDOPTION_DISABLED, "Signature" ) )
735 m_xSignatureBtn->set_sensitive(false);
736 }
737
~SfxDocumentPage()738 SfxDocumentPage::~SfxDocumentPage()
739 {
740 }
741
IMPL_LINK_NOARG(SfxDocumentPage,DeleteHdl,weld::Button &,void)742 IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
743 {
744 OUString aName;
745 if (bEnableUseUserData && m_xUseUserDataCB->get_active())
746 aName = SvtUserOptions().GetFullName();
747 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
748 DateTime now( DateTime::SYSTEM );
749 util::DateTime uDT( now.GetUNODateTime() );
750 m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
751 m_xChangeValFt->set_label( "" );
752 m_xPrintValFt->set_label( "" );
753 const tools::Time aTime( 0 );
754 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aTime ) );
755 m_xDocNoValFt->set_label(OUString('1'));
756 bHandleDelete = true;
757 }
758
IMPL_LINK_NOARG(SfxDocumentPage,SignatureHdl,weld::Button &,void)759 IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
760 {
761 SfxObjectShell* pDoc = SfxObjectShell::Current();
762 if( pDoc )
763 {
764 pDoc->SignDocumentContent(GetFrameWeld());
765
766 ImplUpdateSignatures();
767 }
768 }
769
IMPL_LINK_NOARG(SfxDocumentPage,ChangePassHdl,weld::Button &,void)770 IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
771 {
772 SfxObjectShell* pShell = SfxObjectShell::Current();
773 do
774 {
775 if (!pShell)
776 break;
777 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
778 if (!pMedSet)
779 break;
780 std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
781 if (!pFilter)
782 break;
783
784 sfx2::RequestPassword(pFilter, OUString(), pMedSet, GetFrameWeld()->GetXWindow());
785 pShell->SetModified();
786 }
787 while (false);
788 }
789
ImplUpdateSignatures()790 void SfxDocumentPage::ImplUpdateSignatures()
791 {
792 SfxObjectShell* pDoc = SfxObjectShell::Current();
793 if ( !pDoc )
794 return;
795
796 SfxMedium* pMedium = pDoc->GetMedium();
797 if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
798 return;
799
800 Reference< security::XDocumentDigitalSignatures > xD;
801 try
802 {
803 xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
804 xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
805 }
806 catch ( const css::uno::DeploymentException& )
807 {
808 }
809 OUString s;
810 Sequence< security::DocumentSignatureInformation > aInfos;
811
812 if ( xD.is() )
813 aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
814 uno::Reference< io::XInputStream >() );
815 if ( aInfos.getLength() > 1 )
816 s = m_aMultiSignedStr;
817 else if ( aInfos.getLength() == 1 )
818 {
819 const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
820 s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
821 comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
822 }
823 m_xSignedValFt->set_label(s);
824 }
825
ImplCheckPasswordState()826 void SfxDocumentPage::ImplCheckPasswordState()
827 {
828 SfxObjectShell* pShell = SfxObjectShell::Current();
829 do
830 {
831 if (!pShell)
832 break;
833 SfxItemSet* pMedSet = pShell->GetMedium()->GetItemSet();
834 if (!pMedSet)
835 break;
836 const SfxUnoAnyItem* pEncryptionDataItem = SfxItemSet::GetItem<SfxUnoAnyItem>(pMedSet, SID_ENCRYPTIONDATA, false);
837 uno::Sequence< beans::NamedValue > aEncryptionData;
838 if (pEncryptionDataItem)
839 pEncryptionDataItem->GetValue() >>= aEncryptionData;
840 else
841 break;
842
843 if (!aEncryptionData.hasElements())
844 break;
845 m_xChangePassBtn->set_sensitive(true);
846 return;
847 }
848 while (false);
849 m_xChangePassBtn->set_sensitive(false);
850 }
851
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)852 std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
853 {
854 return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
855 }
856
EnableUseUserData()857 void SfxDocumentPage::EnableUseUserData()
858 {
859 bEnableUseUserData = true;
860 m_xUseUserDataCB->show();
861 m_xDeleteBtn->show();
862 }
863
FillItemSet(SfxItemSet * rSet)864 bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
865 {
866 bool bRet = false;
867
868 if ( !bHandleDelete && bEnableUseUserData &&
869 m_xUseUserDataCB->get_state_changed_from_saved() )
870 {
871 const SfxItemSet* pExpSet = GetDialogExampleSet();
872 const SfxPoolItem* pItem;
873
874 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
875 {
876 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
877 bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
878 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
879 rSet->Put( *pInfoItem );
880 bRet = true;
881 }
882 }
883
884 if ( bHandleDelete )
885 {
886 const SfxItemSet* pExpSet = GetDialogExampleSet();
887 const SfxPoolItem* pItem;
888 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
889 {
890 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
891 bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
892 SfxDocumentInfoItem newItem( *pInfoItem );
893 newItem.resetUserData( bUseAuthor
894 ? SvtUserOptions().GetFullName()
895 : OUString() );
896 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
897 newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
898
899 newItem.SetDeleteUserData( true );
900 rSet->Put( newItem );
901 bRet = true;
902 }
903 }
904
905 if ( m_xUseThumbnailSaveCB->get_state_changed_from_saved() )
906 {
907 const SfxItemSet* pExpSet = GetDialogExampleSet();
908 const SfxPoolItem* pItem;
909
910 if ( pExpSet && SfxItemState::SET == pExpSet->GetItemState( SID_DOCINFO, true, &pItem ) )
911 {
912 const SfxDocumentInfoItem* pInfoItem = static_cast<const SfxDocumentInfoItem*>(pItem);
913 bool bUseThumbnail = ( TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state() );
914 const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave( bUseThumbnail );
915 rSet->Put( *pInfoItem );
916 bRet = true;
917 }
918 }
919
920 return bRet;
921 }
922
Reset(const SfxItemSet * rSet)923 void SfxDocumentPage::Reset( const SfxItemSet* rSet )
924 {
925 // Determine the document information
926 const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
927
928 // template data
929 if (rInfoItem.HasTemplate())
930 {
931 const OUString& rName = rInfoItem.getTemplateName();
932 if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
933 m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
934 else
935 m_xTemplValFt->set_label(rName);
936 }
937 else
938 {
939 m_xTemplFt->hide();
940 m_xTemplValFt->hide();
941 }
942
943 // determine file name
944 OUString aFile( rInfoItem.GetValue() );
945 OUString aFactory( aFile );
946 if ( aFile.getLength() > 2 && aFile[0] == '[' )
947 {
948 sal_Int32 nPos = aFile.indexOf( ']' );
949 aFactory = aFile.copy( 1, nPos-1 );
950 aFile = aFile.copy( nPos+1 );
951 }
952
953 // determine name
954 INetURLObject aURL(aFile);
955 OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
956 if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
957 aName = SfxResId( STR_NONAME );
958 m_xNameED->set_label( aName );
959
960 // determine context symbol
961 aURL.SetSmartProtocol( INetProtocol::File );
962 aURL.SetSmartURL( aFactory);
963 const OUString& rMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
964 OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
965 m_xBmp->set_from_icon_name(aImage);
966
967 // determine size and type
968 OUString aSizeText( m_aUnknownSize );
969 if ( aURL.GetProtocol() == INetProtocol::File ||
970 aURL.isAnyKnownWebDAVScheme() )
971 aSizeText = CreateSizeText( SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ) );
972 m_xShowSizeFT->set_label( aSizeText );
973
974 OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(rMainURL) );
975 if ( aDescription.isEmpty() )
976 aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
977 m_xShowTypeFT->set_label( aDescription );
978
979 // determine location
980 aURL.SetSmartURL( aFile);
981 if ( aURL.GetProtocol() == INetProtocol::File )
982 {
983 INetURLObject aPath( aURL );
984 aPath.setFinalSlash();
985 aPath.removeSegment();
986 // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
987 aPath.removeFinalSlash();
988 OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
989 m_xFileValEd->set_label( aText );
990 }
991 else if ( aURL.GetProtocol() != INetProtocol::PrivSoffice )
992 m_xFileValEd->set_label( aURL.GetPartBeforeLastName() );
993
994 // handle access data
995 bool bUseUserData = rInfoItem.IsUseUserData();
996 const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
997 m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
998 rInfoItem.getCreationDate(), rLocaleWrapper ) );
999 util::DateTime aTime( rInfoItem.getModificationDate() );
1000 if ( aTime.Month > 0 )
1001 m_xChangeValFt->set_label( ConvertDateTime_Impl(
1002 rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
1003 aTime = rInfoItem.getPrintDate();
1004 if ( aTime.Month > 0 )
1005 m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
1006 aTime, rLocaleWrapper ) );
1007 const long nTime = rInfoItem.getEditingDuration();
1008 if ( bUseUserData )
1009 {
1010 const tools::Time aT( nTime/3600, (nTime%3600)/60, nTime%60 );
1011 m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aT ) );
1012 m_xDocNoValFt->set_label( OUString::number(
1013 rInfoItem.getEditingCycles() ) );
1014 }
1015
1016 bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1017
1018 // Check for cmis properties where otherwise unavailable
1019 if ( rInfoItem.isCmisDocument( ) )
1020 {
1021 const uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
1022 for ( const auto& rCmisProp : aCmisProps )
1023 {
1024 if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1025 aSizeText == m_aUnknownSize )
1026 {
1027 Sequence< sal_Int64 > seqValue;
1028 rCmisProp.Value >>= seqValue;
1029 SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1030 Application::GetSettings().GetLanguageTag().getLanguageType() );
1031 sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1032 if ( seqValue.hasElements() )
1033 {
1034 OUString sValue;
1035 aNumberFormatter.GetInputLineString( seqValue[0], nIndex, sValue );
1036 m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1037 }
1038 }
1039
1040 util::DateTime uDT;
1041 OUString emptyDate = ConvertDateTime_Impl( "", uDT, rLocaleWrapper );
1042 if ( rCmisProp.Id == "cmis:creationDate" &&
1043 (m_xCreateValFt->get_label() == emptyDate ||
1044 m_xCreateValFt->get_label().isEmpty()))
1045 {
1046 Sequence< util::DateTime > seqValue;
1047 rCmisProp.Value >>= seqValue;
1048 if ( seqValue.hasElements() )
1049 {
1050 m_xCreateValFt->set_label( ConvertDateTime_Impl( "", seqValue[0], rLocaleWrapper ) );
1051 }
1052 }
1053 if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1054 (m_xChangeValFt->get_label() == emptyDate ||
1055 m_xChangeValFt->get_label().isEmpty()))
1056 {
1057 Sequence< util::DateTime > seqValue;
1058 rCmisProp.Value >>= seqValue;
1059 if ( seqValue.hasElements() )
1060 {
1061 m_xChangeValFt->set_label( ConvertDateTime_Impl( "", seqValue[0], rLocaleWrapper ) );
1062 }
1063 }
1064 }
1065 }
1066
1067 m_xUseUserDataCB->set_active(bUseUserData);
1068 m_xUseUserDataCB->save_state();
1069 m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1070 bHandleDelete = false;
1071 m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1072 m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1073 m_xUseThumbnailSaveCB->save_state();
1074 }
1075
SfxDocumentInfoDialog(weld::Window * pParent,const SfxItemSet & rItemSet)1076 SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1077 : SfxTabDialogController(pParent, "sfx/ui/documentpropertiesdialog.ui",
1078 "DocumentPropertiesDialog", &rItemSet)
1079 {
1080 const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1081
1082 #ifdef DBG_UTIL
1083 const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1084 DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1085 #endif
1086
1087 // Determine the Titles
1088 const SfxPoolItem* pItem = nullptr;
1089 OUString aTitle(m_xDialog->get_title());
1090 if ( SfxItemState::SET !=
1091 rItemSet.GetItemState( SID_EXPLORER_PROPS_START, false, &pItem ) )
1092 {
1093 // File name
1094 const OUString& aFile( rInfoItem.GetValue() );
1095
1096 INetURLObject aURL;
1097 aURL.SetSmartProtocol( INetProtocol::File );
1098 aURL.SetSmartURL( aFile);
1099 if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1100 {
1101 OUString aLastName( aURL.GetLastName() );
1102 if ( !aLastName.isEmpty() )
1103 aTitle = aTitle.replaceFirst("%1", aLastName);
1104 else
1105 aTitle = aTitle.replaceFirst("%1", aFile);
1106 }
1107 else
1108 aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1109 }
1110 else
1111 {
1112 DBG_ASSERT( dynamic_cast<const SfxStringItem *>(pItem) != nullptr,
1113 "SfxDocumentInfoDialog:<SfxStringItem> expected" );
1114 aTitle = aTitle.replaceFirst("%1", static_cast<const SfxStringItem*>(pItem)->GetValue());
1115 }
1116 m_xDialog->set_title(aTitle);
1117
1118 // Property Pages
1119 AddTabPage("general", SfxDocumentPage::Create, nullptr);
1120 AddTabPage("description", SfxDocumentDescPage::Create, nullptr);
1121 AddTabPage("customprops", SfxCustomPropertiesPage::Create, nullptr);
1122 if (rInfoItem.isCmisDocument())
1123 AddTabPage("cmisprops", SfxCmisPropertiesPage::Create, nullptr);
1124 else
1125 RemoveTabPage("cmisprops");
1126 AddTabPage("security", SfxSecurityPage::Create, nullptr);
1127 }
1128
PageCreated(const OString & rId,SfxTabPage & rPage)1129 void SfxDocumentInfoDialog::PageCreated(const OString& rId, SfxTabPage &rPage)
1130 {
1131 if (rId == "general")
1132 static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1133 }
1134
AddFontTabPage()1135 void SfxDocumentInfoDialog::AddFontTabPage()
1136 {
1137 AddTabPage("font", SfxResId(STR_FONT_TABPAGE), SfxDocumentFontsPage::Create);
1138 }
1139
1140 // class CustomPropertiesYesNoButton -------------------------------------
1141
CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,std::unique_ptr<weld::RadioButton> xYesButton,std::unique_ptr<weld::RadioButton> xNoButton)1142 CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1143 std::unique_ptr<weld::RadioButton> xYesButton,
1144 std::unique_ptr<weld::RadioButton> xNoButton)
1145 : m_xTopLevel(std::move(xTopLevel))
1146 , m_xYesButton(std::move(xYesButton))
1147 , m_xNoButton(std::move(xNoButton))
1148 {
1149 CheckNo();
1150 }
1151
~CustomPropertiesYesNoButton()1152 CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1153 {
1154 }
1155
1156 class DurationDialog_Impl : public weld::GenericDialogController
1157 {
1158 std::unique_ptr<weld::CheckButton> m_xNegativeCB;
1159 std::unique_ptr<weld::SpinButton> m_xYearNF;
1160 std::unique_ptr<weld::SpinButton> m_xMonthNF;
1161 std::unique_ptr<weld::SpinButton> m_xDayNF;
1162 std::unique_ptr<weld::SpinButton> m_xHourNF;
1163 std::unique_ptr<weld::SpinButton> m_xMinuteNF;
1164 std::unique_ptr<weld::SpinButton> m_xSecondNF;
1165 std::unique_ptr<weld::SpinButton> m_xMSecondNF;
1166
1167 public:
1168 DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration);
1169 util::Duration GetDuration() const;
1170 };
1171
DurationDialog_Impl(weld::Widget * pParent,const util::Duration & rDuration)1172 DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1173 : GenericDialogController(pParent, "sfx/ui/editdurationdialog.ui", "EditDurationDialog")
1174 , m_xNegativeCB(m_xBuilder->weld_check_button("negative"))
1175 , m_xYearNF(m_xBuilder->weld_spin_button("years"))
1176 , m_xMonthNF(m_xBuilder->weld_spin_button("months"))
1177 , m_xDayNF(m_xBuilder->weld_spin_button("days"))
1178 , m_xHourNF(m_xBuilder->weld_spin_button("hours"))
1179 , m_xMinuteNF(m_xBuilder->weld_spin_button("minutes"))
1180 , m_xSecondNF(m_xBuilder->weld_spin_button("seconds"))
1181 , m_xMSecondNF(m_xBuilder->weld_spin_button("milliseconds"))
1182 {
1183 m_xNegativeCB->set_active(rDuration.Negative);
1184 m_xYearNF->set_value(rDuration.Years);
1185 m_xMonthNF->set_value(rDuration.Months);
1186 m_xDayNF->set_value(rDuration.Days);
1187 m_xHourNF->set_value(rDuration.Hours);
1188 m_xMinuteNF->set_value(rDuration.Minutes);
1189 m_xSecondNF->set_value(rDuration.Seconds);
1190 m_xMSecondNF->set_value(rDuration.NanoSeconds);
1191 }
1192
GetDuration() const1193 util::Duration DurationDialog_Impl::GetDuration() const
1194 {
1195 util::Duration aRet;
1196 aRet.Negative = m_xNegativeCB->get_active();
1197 aRet.Years = m_xYearNF->get_value();
1198 aRet.Months = m_xMonthNF->get_value();
1199 aRet.Days = m_xDayNF->get_value();
1200 aRet.Hours = m_xHourNF->get_value();
1201 aRet.Minutes = m_xMinuteNF->get_value();
1202 aRet.Seconds = m_xSecondNF->get_value();
1203 aRet.NanoSeconds = m_xMSecondNF->get_value();
1204 return aRet;
1205 }
1206
CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,std::unique_ptr<weld::Button> xEditButton)1207 CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1208 std::unique_ptr<weld::Button> xEditButton)
1209 : m_xEntry(std::move(xEntry))
1210 , m_xEditButton(std::move(xEditButton))
1211 {
1212 m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1213 SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1214 }
1215
set_visible(bool bVisible)1216 void CustomPropertiesDurationField::set_visible(bool bVisible)
1217 {
1218 m_xEntry->set_visible(bVisible);
1219 m_xEditButton->set_visible(bVisible);
1220 }
1221
SetDuration(const util::Duration & rDuration)1222 void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1223 {
1224 m_aDuration = rDuration;
1225 OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1226 SfxResId(SFX_ST_DURATION_FORMAT);
1227 sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1228 sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1229 sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days ) );
1230 sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours ) );
1231 sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1232 sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1233 m_xEntry->set_text(sText);
1234 }
1235
IMPL_LINK(CustomPropertiesDurationField,ClickHdl,weld::Button &,rButton,void)1236 IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1237 {
1238 DurationDialog_Impl aDurationDlg(&rButton, GetDuration());
1239 if (aDurationDlg.run() == RET_OK)
1240 SetDuration(aDurationDlg.GetDuration());
1241 }
1242
1243 namespace
1244 {
fillNameBox(weld::ComboBox & rNameBox)1245 void fillNameBox(weld::ComboBox& rNameBox)
1246 {
1247 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_CB_PROPERTY_STRINGARRAY); ++i)
1248 rNameBox.append_text(SfxResId(SFX_CB_PROPERTY_STRINGARRAY[i]));
1249 Size aSize(rNameBox.get_preferred_size());
1250 rNameBox.set_size_request(aSize.Width(), aSize.Height());
1251 }
1252
fillTypeBox(weld::ComboBox & rTypeBox)1253 void fillTypeBox(weld::ComboBox& rTypeBox)
1254 {
1255 for (size_t i = 0; i < SAL_N_ELEMENTS(SFX_LB_PROPERTY_STRINGARRAY); ++i)
1256 {
1257 OUString sId(OUString::number(SFX_LB_PROPERTY_STRINGARRAY[i].second));
1258 rTypeBox.append(sId, SfxResId(SFX_LB_PROPERTY_STRINGARRAY[i].first));
1259 }
1260 rTypeBox.set_active(0);
1261 Size aSize(rTypeBox.get_preferred_size());
1262 rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1263 }
1264 }
1265
1266 // struct CustomPropertyLine ---------------------------------------------
CustomPropertyLine(CustomPropertiesWindow * pParent,weld::Widget * pContainer)1267 CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1268 : m_pParent(pParent)
1269 , m_xBuilder(Application::CreateBuilder(pContainer, "sfx/ui/linefragment.ui"))
1270 , m_xLine(m_xBuilder->weld_container("lineentry"))
1271 , m_xNameBox(m_xBuilder->weld_combo_box("namebox"))
1272 , m_xTypeBox(m_xBuilder->weld_combo_box("typebox"))
1273 , m_xValueEdit(m_xBuilder->weld_entry("valueedit"))
1274 , m_xDateTimeBox(m_xBuilder->weld_widget("datetimebox"))
1275 , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date"))))
1276 , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_time_spin_button("time", TimeFieldFormat::F_SEC)))
1277 , m_xDurationBox(m_xBuilder->weld_widget("durationbox"))
1278 , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry("duration"),
1279 m_xBuilder->weld_button("durationbutton")))
1280 , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget("yesno"),
1281 m_xBuilder->weld_radio_button("yes"),
1282 m_xBuilder->weld_radio_button("no")))
1283 , m_xRemoveButton(m_xBuilder->weld_button("remove"))
1284 , m_bTypeLostFocus( false )
1285 {
1286 fillNameBox(*m_xNameBox);
1287 fillTypeBox(*m_xTypeBox);
1288
1289 m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1290 m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1291 m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1292 //add lose focus handlers of date/time fields
1293 m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1294 }
1295
Clear()1296 void CustomPropertyLine::Clear()
1297 {
1298 m_xNameBox->set_active(-1);
1299 m_xValueEdit->set_text(OUString());
1300
1301 }
1302
Hide()1303 void CustomPropertyLine::Hide()
1304 {
1305 m_xLine->hide();
1306 }
1307
CustomPropertiesWindow(weld::Container & rParent,weld::Label & rHeaderAccName,weld::Label & rHeaderAccType,weld::Label & rHeaderAccValue)1308 CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1309 weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1310 : m_nHeight(0)
1311 , m_nLineHeight(0)
1312 , m_nScrollPos(0)
1313 , m_pCurrentLine(nullptr)
1314 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1315 Application::GetSettings().GetLanguageTag().getLanguageType())
1316 , m_rBody(rParent)
1317 , m_rHeaderAccName(rHeaderAccName)
1318 , m_rHeaderAccType(rHeaderAccType)
1319 , m_rHeaderAccValue(rHeaderAccValue)
1320 {
1321 m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1322 m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1323 m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1324 m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1325 }
1326
~CustomPropertiesWindow()1327 CustomPropertiesWindow::~CustomPropertiesWindow()
1328 {
1329 m_aEditLoseFocusIdle.Stop();
1330 m_aBoxLoseFocusIdle.Stop();
1331
1332 m_pCurrentLine = nullptr;
1333 }
1334
DoTypeHdl(const weld::ComboBox & rBox)1335 void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1336 {
1337 auto nType = rBox.get_active_id().toInt32();
1338 m_xValueEdit->set_visible( (CUSTOM_TYPE_TEXT == nType) || (CUSTOM_TYPE_NUMBER == nType) );
1339 m_xDateTimeBox->set_visible( (CUSTOM_TYPE_DATE == nType) || (CUSTOM_TYPE_DATETIME == nType) );
1340 m_xDateField->set_visible( (CUSTOM_TYPE_DATE == nType) || (CUSTOM_TYPE_DATETIME == nType) );
1341 m_xTimeField->set_visible( CUSTOM_TYPE_DATETIME == nType );
1342 m_xDurationBox->set_visible( CUSTOM_TYPE_DURATION == nType );
1343 m_xDurationField->set_visible( CUSTOM_TYPE_DURATION == nType );
1344 m_xYesNoButton->set_visible( CUSTOM_TYPE_BOOLEAN == nType );
1345 }
1346
IMPL_LINK(CustomPropertyLine,TypeHdl,weld::ComboBox &,rBox,void)1347 IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1348 {
1349 DoTypeHdl(rBox);
1350 }
1351
Remove(const CustomPropertyLine * pLine)1352 void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1353 {
1354 StoreCustomProperties();
1355
1356 auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1357 [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1358 if ( pFound != m_aCustomPropertiesLines.end() )
1359 {
1360 sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1361 sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1362 m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1363
1364 ReloadLinesContent();
1365 }
1366
1367 m_aRemovedHdl.Call(nullptr);
1368 }
1369
IMPL_LINK_NOARG(CustomPropertyLine,RemoveHdl,weld::Button &,void)1370 IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1371 {
1372 m_pParent->Remove(this);
1373 }
1374
EditLoseFocus(CustomPropertyLine * pLine)1375 void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1376 {
1377 m_pCurrentLine = pLine;
1378 m_aEditLoseFocusIdle.Start();
1379 }
1380
IMPL_LINK_NOARG(CustomPropertyLine,EditLoseFocusHdl,weld::Widget &,void)1381 IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1382 {
1383 if (!m_bTypeLostFocus)
1384 m_pParent->EditLoseFocus(this);
1385 else
1386 m_bTypeLostFocus = false;
1387 }
1388
BoxLoseFocus(CustomPropertyLine * pLine)1389 void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1390 {
1391 m_pCurrentLine = pLine;
1392 m_aBoxLoseFocusIdle.Start();
1393 }
1394
IMPL_LINK_NOARG(CustomPropertyLine,BoxLoseFocusHdl,weld::Widget &,void)1395 IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1396 {
1397 m_pParent->BoxLoseFocus(this);
1398 }
1399
IMPL_LINK_NOARG(CustomPropertiesWindow,EditTimeoutHdl,Timer *,void)1400 IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1401 {
1402 ValidateLine( m_pCurrentLine, false );
1403 }
1404
IMPL_LINK_NOARG(CustomPropertiesWindow,BoxTimeoutHdl,Timer *,void)1405 IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1406 {
1407 ValidateLine( m_pCurrentLine, true );
1408 }
1409
IsLineValid(CustomPropertyLine * pLine) const1410 bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1411 {
1412 bool bIsValid = true;
1413 pLine->m_bTypeLostFocus = false;
1414 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1415 OUString sValue = pLine->m_xValueEdit->get_text();
1416 if ( sValue.isEmpty() )
1417 return true;
1418
1419 sal_uInt32 nIndex = 0xFFFFFFFF;
1420 if ( CUSTOM_TYPE_NUMBER == nType )
1421 nIndex = const_cast< SvNumberFormatter& >(
1422 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
1423 else if ( CUSTOM_TYPE_DATE == nType )
1424 nIndex = const_cast< SvNumberFormatter& >(
1425 m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1426
1427 if ( nIndex != 0xFFFFFFFF )
1428 {
1429 sal_uInt32 nTemp = nIndex;
1430 double fDummy = 0.0;
1431 bIsValid = const_cast< SvNumberFormatter& >(
1432 m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1433 if ( bIsValid && nTemp != nIndex )
1434 // sValue is a number but the format doesn't match the index
1435 bIsValid = false;
1436 }
1437
1438 return bIsValid;
1439 }
1440
ValidateLine(CustomPropertyLine * pLine,bool bIsFromTypeBox)1441 void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1442 {
1443 if (pLine && !IsLineValid(pLine))
1444 {
1445 if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1446 pLine->m_bTypeLostFocus = true;
1447 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1448 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1449 if (xMessageBox->run() == RET_OK)
1450 pLine->m_xTypeBox->set_active_id(OUString::number(CUSTOM_TYPE_TEXT));
1451 else
1452 pLine->m_xValueEdit->grab_focus();
1453 }
1454 }
1455
SetVisibleLineCount(sal_uInt32 nCount)1456 void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1457 {
1458 while (GetExistingLineCount() < nCount)
1459 {
1460 CreateNewLine();
1461 }
1462 }
1463
AddLine(const OUString & sName,Any const & rAny)1464 void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1465 {
1466 m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1467 ReloadLinesContent();
1468 }
1469
CreateNewLine()1470 void CustomPropertiesWindow::CreateNewLine()
1471 {
1472 CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1473 pNewLine->m_xNameBox->set_accessible_relation_labeled_by(&m_rHeaderAccName);
1474 pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1475 pNewLine->m_xTypeBox->set_accessible_relation_labeled_by(&m_rHeaderAccType);
1476 pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1477 pNewLine->m_xValueEdit->set_accessible_relation_labeled_by(&m_rHeaderAccValue);
1478 pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1479
1480 m_aCustomPropertiesLines.emplace_back( pNewLine );
1481
1482 pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1483 pNewLine->m_xNameBox->grab_focus();
1484 }
1485
AreAllLinesValid() const1486 bool CustomPropertiesWindow::AreAllLinesValid() const
1487 {
1488 bool bRet = true;
1489 for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1490 {
1491 if ( !IsLineValid( pLine.get() ) )
1492 {
1493 bRet = false;
1494 break;
1495 }
1496 }
1497
1498 return bRet;
1499 }
1500
ClearAllLines()1501 void CustomPropertiesWindow::ClearAllLines()
1502 {
1503 for (auto& pLine : m_aCustomPropertiesLines)
1504 {
1505 pLine->Clear();
1506 }
1507 m_pCurrentLine = nullptr;
1508 m_aCustomProperties.clear();
1509 m_nScrollPos = 0;
1510 }
1511
DoScroll(sal_Int32 nNewPos)1512 void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1513 {
1514 StoreCustomProperties();
1515 m_nScrollPos += nNewPos;
1516 ReloadLinesContent();
1517 }
1518
GetCustomProperties()1519 Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1520 {
1521 StoreCustomProperties();
1522
1523 Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1524
1525 for (sal_uInt32 i = 0; i < GetTotalLineCount(); ++i)
1526 {
1527 aPropertiesSeq[i].Name = m_aCustomProperties[i]->m_sName;
1528 aPropertiesSeq[i].Value = m_aCustomProperties[i]->m_aValue;
1529 }
1530
1531 return aPropertiesSeq;
1532 }
1533
CustomPropertiesTimeField(std::unique_ptr<weld::TimeSpinButton> xTimeField)1534 CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::TimeSpinButton> xTimeField)
1535 : m_xTimeField(std::move(xTimeField))
1536 , m_isUTC(false)
1537 {
1538 }
1539
~CustomPropertiesTimeField()1540 CustomPropertiesTimeField::~CustomPropertiesTimeField()
1541 {
1542 }
1543
CustomPropertiesDateField(SvtCalendarBox * pDateField)1544 CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1545 : m_xDateField(pDateField)
1546 {
1547 DateTime aDateTime(DateTime::SYSTEM);
1548 m_xDateField->set_date(aDateTime);
1549 }
1550
~CustomPropertiesDateField()1551 CustomPropertiesDateField::~CustomPropertiesDateField()
1552 {
1553 }
1554
StoreCustomProperties()1555 void CustomPropertiesWindow::StoreCustomProperties()
1556 {
1557 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1558
1559 for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1560 {
1561 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1562
1563 OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1564 if (!sPropertyName.isEmpty())
1565 {
1566 m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1567 auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1568 if (CUSTOM_TYPE_NUMBER == nType)
1569 {
1570 double nValue = 0;
1571 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1572 bool bIsNum = m_aNumberFormatter.
1573 IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1574 if (bIsNum)
1575 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1576 }
1577 else if (CUSTOM_TYPE_BOOLEAN == nType)
1578 {
1579 bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1580 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1581 }
1582 else if (CUSTOM_TYPE_DATETIME == nType)
1583 {
1584 Date aTmpDate = pLine->m_xDateField->get_date();
1585 tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1586 util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1587 aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1588 aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1589 pLine->m_xTimeField->m_isUTC);
1590 if (pLine->m_xDateField->m_TZ.is_initialized())
1591 {
1592 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1593 aDateTime, pLine->m_xDateField->m_TZ.get());
1594 }
1595 else
1596 {
1597 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1598 }
1599 }
1600 else if (CUSTOM_TYPE_DATE == nType)
1601 {
1602 Date aTmpDate = pLine->m_xDateField->get_date();
1603 util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1604 aTmpDate.GetYear());
1605 if (pLine->m_xDateField->m_TZ.is_initialized())
1606 {
1607 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1608 aDate, pLine->m_xDateField->m_TZ.get());
1609 }
1610 else
1611 {
1612 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1613 }
1614 }
1615 else if (CUSTOM_TYPE_DURATION == nType)
1616 {
1617 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1618 }
1619 else
1620 {
1621 OUString sValue(pLine->m_xValueEdit->get_text());
1622 m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1623 }
1624 }
1625 }
1626 }
1627
SetCustomProperties(std::vector<std::unique_ptr<CustomProperty>> && rProperties)1628 void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1629 {
1630 m_aCustomProperties = std::move(rProperties);
1631 ReloadLinesContent();
1632 }
1633
ReloadLinesContent()1634 void CustomPropertiesWindow::ReloadLinesContent()
1635 {
1636 double nTmpValue = 0;
1637 bool bTmpValue = false;
1638 OUString sTmpValue;
1639 util::DateTime aTmpDateTime;
1640 util::Date aTmpDate;
1641 util::DateTimeWithTimezone aTmpDateTimeTZ;
1642 util::DateWithTimezone aTmpDateTZ;
1643 util::Duration aTmpDuration;
1644 SvtSysLocale aSysLocale;
1645 const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1646 sal_IntPtr nType = CUSTOM_TYPE_UNKNOWN;
1647 OUString sValue;
1648
1649 sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1650 sal_uInt32 i = 0;
1651
1652 for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1653 {
1654 const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1655 const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1656
1657 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1658 pLine->Clear();
1659
1660 pLine->m_xNameBox->set_entry_text(rName);
1661 pLine->m_xLine->show();
1662
1663 if (!rAny.hasValue())
1664 {
1665 pLine->m_xValueEdit->set_text(OUString());
1666 }
1667 else if (rAny >>= nTmpValue)
1668 {
1669 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1670 m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex, sValue);
1671 pLine->m_xValueEdit->set_text(sValue);
1672 nType = CUSTOM_TYPE_NUMBER;
1673 }
1674 else if (rAny >>= bTmpValue)
1675 {
1676 sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1677 nType = CUSTOM_TYPE_BOOLEAN;
1678 }
1679 else if (rAny >>= sTmpValue)
1680 {
1681 pLine->m_xValueEdit->set_text(sTmpValue);
1682 nType = CUSTOM_TYPE_TEXT;
1683 }
1684 else if (rAny >>= aTmpDate)
1685 {
1686 pLine->m_xDateField->set_date(Date(aTmpDate));
1687 nType = CUSTOM_TYPE_DATE;
1688 }
1689 else if (rAny >>= aTmpDateTime)
1690 {
1691 pLine->m_xDateField->set_date(Date(aTmpDateTime));
1692 pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1693 pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1694 nType = CUSTOM_TYPE_DATETIME;
1695 }
1696 else if (rAny >>= aTmpDateTZ)
1697 {
1698 pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1699 aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1700 pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1701 nType = CUSTOM_TYPE_DATE;
1702 }
1703 else if (rAny >>= aTmpDateTimeTZ)
1704 {
1705 util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1706 pLine->m_xDateField->set_date(Date(rDT));
1707 pLine->m_xTimeField->set_value(tools::Time(rDT));
1708 pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1709 pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1710 nType = CUSTOM_TYPE_DATETIME;
1711 }
1712 else if (rAny >>= aTmpDuration)
1713 {
1714 nType = CUSTOM_TYPE_DURATION;
1715 pLine->m_xDurationField->SetDuration(aTmpDuration);
1716 }
1717
1718 if (nType != CUSTOM_TYPE_UNKNOWN)
1719 {
1720 if (CUSTOM_TYPE_BOOLEAN == nType)
1721 {
1722 if (bTmpValue)
1723 pLine->m_xYesNoButton->CheckYes();
1724 else
1725 pLine->m_xYesNoButton->CheckNo();
1726 }
1727 pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1728 }
1729
1730 pLine->DoTypeHdl(*pLine->m_xTypeBox);
1731 }
1732
1733 while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
1734 {
1735 CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1736 pLine->Hide();
1737 i++;
1738 }
1739 }
1740
CustomPropertiesControl()1741 CustomPropertiesControl::CustomPropertiesControl()
1742 : m_nThumbPos(0)
1743 {
1744 }
1745
Init(weld::Builder & rBuilder)1746 void CustomPropertiesControl::Init(weld::Builder& rBuilder)
1747 {
1748 m_xBox = rBuilder.weld_widget("box");
1749 m_xBody = rBuilder.weld_container("properties");
1750
1751 m_xName = rBuilder.weld_label("name");
1752 m_xType = rBuilder.weld_label("type");
1753 m_xValue = rBuilder.weld_label("value");
1754 m_xVertScroll = rBuilder.weld_scrolled_window("scroll");
1755 m_xVertScroll->set_user_managed_scrolling();
1756 m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
1757
1758 m_xBox->set_stack_background();
1759 m_xVertScroll->show();
1760
1761 std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
1762 Size aLineSize(xNewLine->m_xLine->get_preferred_size());
1763 m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
1764 m_xBody->set_size_request(aLineSize.Width() + 6, -1);
1765 auto nHeight = aLineSize.Height() * 8;
1766 m_xVertScroll->set_size_request(-1, nHeight + 6);
1767
1768 m_xPropertiesWin->SetHeight(nHeight);
1769 m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
1770
1771 m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
1772 m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
1773 m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
1774
1775 m_xBody->move(xNewLine->m_xLine.get(), nullptr);
1776 xNewLine.reset();
1777
1778 m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
1779
1780 m_xVertScroll->vadjustment_set_lower(0);
1781 m_xVertScroll->vadjustment_set_upper(0);
1782 m_xVertScroll->vadjustment_set_page_size(0xFFFF);
1783
1784 Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
1785 m_xVertScroll->connect_vadjustment_changed(aScrollLink);
1786
1787 ResizeHdl(Size(-1, nHeight));
1788 }
1789
IMPL_LINK(CustomPropertiesControl,ResizeHdl,const Size &,rSize,void)1790 IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
1791 {
1792 int nHeight = rSize.Height() - 6;
1793 if (nHeight == m_xPropertiesWin->GetHeight())
1794 return;
1795 m_xPropertiesWin->SetHeight(nHeight);
1796 sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
1797 sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
1798 m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
1799 m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
1800 m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
1801 m_xPropertiesWin->ReloadLinesContent();
1802 }
1803
~CustomPropertiesControl()1804 CustomPropertiesControl::~CustomPropertiesControl()
1805 {
1806 }
1807
IMPL_LINK(CustomPropertiesControl,ScrollHdl,weld::ScrolledWindow &,rScrollBar,void)1808 IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
1809 {
1810 sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
1811 int nThumbPos = rScrollBar.vadjustment_get_value();
1812 nOffset *= ( m_nThumbPos - nThumbPos );
1813 m_nThumbPos = nThumbPos;
1814 m_xPropertiesWin->DoScroll( nOffset );
1815 }
1816
IMPL_LINK_NOARG(CustomPropertiesControl,RemovedHdl,void *,void)1817 IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
1818 {
1819 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1820 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1821 if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
1822 {
1823 m_xVertScroll->vadjustment_set_value(nLineCount - 1);
1824 ScrollHdl(*m_xVertScroll);
1825 }
1826 }
1827
AddLine(Any const & rAny)1828 void CustomPropertiesControl::AddLine( Any const & rAny )
1829 {
1830 m_xPropertiesWin->AddLine( OUString(), rAny );
1831 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1832 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1833 if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
1834 {
1835 m_xVertScroll->vadjustment_set_value(nLineCount + 1);
1836 ScrollHdl(*m_xVertScroll);
1837 }
1838 }
1839
SetCustomProperties(std::vector<std::unique_ptr<CustomProperty>> && rProperties)1840 void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1841 {
1842 m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
1843 auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
1844 m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
1845 }
1846
1847 // class SfxCustomPropertiesPage -----------------------------------------
SfxCustomPropertiesPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)1848 SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
1849 : SfxTabPage(pPage, pController, "sfx/ui/custominfopage.ui", "CustomInfoPage", &rItemSet)
1850 , m_xPropertiesCtrl(new CustomPropertiesControl)
1851 , m_xAdd(m_xBuilder->weld_button("add"))
1852 {
1853 m_xPropertiesCtrl->Init(*m_xBuilder);
1854 m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
1855 }
1856
~SfxCustomPropertiesPage()1857 SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
1858 {
1859 m_xPropertiesCtrl.reset();
1860 }
1861
IMPL_LINK_NOARG(SfxCustomPropertiesPage,AddHdl,weld::Button &,void)1862 IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
1863 {
1864 // tdf#115853: reload current lines before adding a brand new one
1865 // indeed the info are deleted by ClearCustomProperties
1866 // each time SfxDocumentInfoItem destructor is called
1867 SfxDocumentInfoItem pInfo;
1868 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1869 for ( const auto& rProperty : aPropertySeq )
1870 {
1871 if ( !rProperty.Name.isEmpty() )
1872 {
1873 pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
1874 }
1875 }
1876
1877 Any aAny;
1878 m_xPropertiesCtrl->AddLine(aAny);
1879 }
1880
FillItemSet(SfxItemSet * rSet)1881 bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
1882 {
1883 const SfxPoolItem* pItem = nullptr;
1884 SfxDocumentInfoItem* pInfo = nullptr;
1885 bool bMustDelete = false;
1886
1887 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
1888 {
1889 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
1890 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
1891 else
1892 {
1893 bMustDelete = true;
1894 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
1895 }
1896 }
1897
1898 if ( pInfo )
1899 {
1900 // If it's a CMIS document, we can't save custom properties
1901 if ( pInfo->isCmisDocument( ) )
1902 {
1903 if ( bMustDelete )
1904 delete pInfo;
1905 return false;
1906 }
1907
1908 pInfo->ClearCustomProperties();
1909 const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
1910 for ( const auto& rProperty : aPropertySeq )
1911 {
1912 if ( !rProperty.Name.isEmpty() )
1913 pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
1914 }
1915 }
1916
1917 if (pInfo)
1918 {
1919 rSet->Put(*pInfo);
1920 if ( bMustDelete )
1921 delete pInfo;
1922 }
1923 return true;
1924 }
1925
Reset(const SfxItemSet * rItemSet)1926 void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
1927 {
1928 m_xPropertiesCtrl->ClearAllLines();
1929 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
1930 std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
1931 m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
1932 }
1933
DeactivatePage(SfxItemSet *)1934 DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
1935 {
1936 DeactivateRC nRet = DeactivateRC::LeavePage;
1937 if ( !m_xPropertiesCtrl->AreAllLinesValid() )
1938 nRet = DeactivateRC::KeepPage;
1939 return nRet;
1940 }
1941
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)1942 std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
1943 {
1944 return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
1945 }
1946
CmisValue(weld::Widget * pParent,const OUString & aStr)1947 CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
1948 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1949 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1950 , m_xValueEdit(m_xBuilder->weld_entry("value"))
1951 {
1952 m_xValueEdit->show();
1953 m_xValueEdit->set_text(aStr);
1954 }
1955
CmisDateTime(weld::Widget * pParent,const util::DateTime & aDateTime)1956 CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
1957 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1958 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1959 , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button("date")))
1960 , m_xTimeField(m_xBuilder->weld_time_spin_button("time", TimeFieldFormat::F_SEC))
1961 {
1962 m_xDateField->show();
1963 m_xTimeField->show();
1964 m_xDateField->set_date(Date(aDateTime));
1965 m_xTimeField->set_value(tools::Time(aDateTime));
1966 }
1967
CmisYesNo(weld::Widget * pParent,bool bValue)1968 CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
1969 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1970 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1971 , m_xYesButton(m_xBuilder->weld_radio_button("yes"))
1972 , m_xNoButton(m_xBuilder->weld_radio_button("no"))
1973 {
1974 m_xYesButton->show();
1975 m_xNoButton->show();
1976 if (bValue)
1977 m_xYesButton->set_active(true);
1978 else
1979 m_xNoButton->set_active(true);
1980 }
1981
1982 // struct CmisPropertyLine ---------------------------------------------
CmisPropertyLine(weld::Widget * pParent)1983 CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
1984 : m_xBuilder(Application::CreateBuilder(pParent, "sfx/ui/cmisline.ui"))
1985 , m_sType(CMIS_TYPE_STRING)
1986 , m_bUpdatable(false)
1987 , m_bRequired(false)
1988 , m_bMultiValued(false)
1989 , m_bOpenChoice(false)
1990 , m_xFrame(m_xBuilder->weld_frame("CmisFrame"))
1991 , m_xName(m_xBuilder->weld_label("name"))
1992 , m_xType(m_xBuilder->weld_label("type"))
1993 {
1994 m_xFrame->set_sensitive(true);
1995 }
1996
~CmisPropertyLine()1997 CmisPropertyLine::~CmisPropertyLine( )
1998 {
1999 }
2000
2001 // class CmisPropertiesWindow -----------------------------------------
2002
CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)2003 CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2004 : m_xBox(std::move(xParent))
2005 , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2006 Application::GetSettings().GetLanguageTag().getLanguageType())
2007 {
2008 }
2009
~CmisPropertiesWindow()2010 CmisPropertiesWindow::~CmisPropertiesWindow()
2011 {
2012 }
2013
ClearAllLines()2014 void CmisPropertiesWindow::ClearAllLines()
2015 {
2016 m_aCmisPropertiesLines.clear();
2017 }
2018
AddLine(const OUString & sId,const OUString & sName,const OUString & sType,const bool bUpdatable,const bool bRequired,const bool bMultiValued,const bool bOpenChoice,Any &,Any const & rAny)2019 void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2020 const OUString& sType, const bool bUpdatable,
2021 const bool bRequired, const bool bMultiValued,
2022 const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2023 {
2024 std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2025
2026 pNewLine->m_sId = sId;
2027 pNewLine->m_sType = sType;
2028 pNewLine->m_bUpdatable = bUpdatable;
2029 pNewLine->m_bRequired = bRequired;
2030 pNewLine->m_bMultiValued = bMultiValued;
2031 pNewLine->m_bOpenChoice = bOpenChoice;
2032
2033 if ( sType == CMIS_TYPE_INTEGER )
2034 {
2035 Sequence< sal_Int64 > seqValue;
2036 rAny >>= seqValue;
2037 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2038 for ( const auto& rValue : std::as_const(seqValue) )
2039 {
2040 OUString sValue;
2041 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2042 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2043 pValue->m_xValueEdit->set_editable(bUpdatable);
2044 pNewLine->m_aValues.push_back( std::move(pValue) );
2045 }
2046 }
2047 else if ( sType == CMIS_TYPE_DECIMAL )
2048 {
2049 Sequence< double > seqValue;
2050 rAny >>= seqValue;
2051 sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2052 for ( const auto& rValue : std::as_const(seqValue) )
2053 {
2054 OUString sValue;
2055 m_aNumberFormatter.GetInputLineString( rValue, nIndex, sValue );
2056 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2057 pValue->m_xValueEdit->set_editable(bUpdatable);
2058 pNewLine->m_aValues.push_back( std::move(pValue) );
2059 }
2060
2061 }
2062 else if ( sType == CMIS_TYPE_BOOL )
2063 {
2064 Sequence<sal_Bool> seqValue;
2065 rAny >>= seqValue;
2066 for ( const auto& rValue : std::as_const(seqValue) )
2067 {
2068 std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2069 pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2070 pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2071 pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2072 }
2073 }
2074 else if ( sType == CMIS_TYPE_STRING )
2075 {
2076 Sequence< OUString > seqValue;
2077 rAny >>= seqValue;
2078 for ( const auto& rValue : std::as_const(seqValue) )
2079 {
2080 std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2081 pValue->m_xValueEdit->set_editable(bUpdatable);
2082 pNewLine->m_aValues.push_back( std::move(pValue) );
2083 }
2084 }
2085 else if ( sType == CMIS_TYPE_DATETIME )
2086 {
2087 Sequence< util::DateTime > seqValue;
2088 rAny >>= seqValue;
2089 for ( const auto& rValue : std::as_const(seqValue) )
2090 {
2091 std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2092 pDateTime->m_xDateField->set_sensitive(bUpdatable);
2093 pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2094 pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2095 }
2096 }
2097 pNewLine->m_xName->set_label( sName );
2098 pNewLine->m_xName->show();
2099 pNewLine->m_xType->set_label( sType );
2100 pNewLine->m_xType->show();
2101
2102 m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2103 }
2104
GetCmisProperties() const2105 Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2106 {
2107 Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2108 sal_Int32 i = 0;
2109 for ( auto& rxLine : m_aCmisPropertiesLines )
2110 {
2111 CmisPropertyLine* pLine = rxLine.get();
2112
2113 aPropertiesSeq[i].Id = pLine->m_sId;
2114 aPropertiesSeq[i].Type = pLine->m_sType;
2115 aPropertiesSeq[i].Updatable = pLine->m_bUpdatable;
2116 aPropertiesSeq[i].Required = pLine->m_bRequired;
2117 aPropertiesSeq[i].OpenChoice = pLine->m_bOpenChoice;
2118 aPropertiesSeq[i].MultiValued = pLine->m_bMultiValued;
2119
2120 OUString sPropertyName = pLine->m_xName->get_label();
2121 if ( !sPropertyName.isEmpty() )
2122 {
2123 aPropertiesSeq[i].Name = sPropertyName;
2124 OUString sType = pLine->m_xType->get_label();
2125 if ( CMIS_TYPE_DECIMAL == sType )
2126 {
2127 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2128 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2129 Sequence< double > seqValue( pLine->m_aValues.size( ) );
2130 sal_Int32 k = 0;
2131 for ( const auto& rxValue : pLine->m_aValues )
2132 {
2133 double dValue = 0.0;
2134 OUString sValue( rxValue->m_xValueEdit->get_text() );
2135 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2136 IsNumberFormat( sValue, nIndex, dValue );
2137 if ( bIsNum )
2138 seqValue[k] = dValue;
2139 ++k;
2140 }
2141 aPropertiesSeq[i].Value <<= seqValue;
2142 }
2143 else if ( CMIS_TYPE_INTEGER == sType )
2144 {
2145 sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2146 m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2147 Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2148 sal_Int32 k = 0;
2149 for ( const auto& rxValue : pLine->m_aValues )
2150 {
2151 double dValue = 0;
2152 OUString sValue( rxValue->m_xValueEdit->get_text() );
2153 bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2154 IsNumberFormat( sValue, nIndex, dValue );
2155 if ( bIsNum )
2156 seqValue[k] = static_cast<sal_Int64>(dValue);
2157 ++k;
2158 }
2159 aPropertiesSeq[i].Value <<= seqValue;
2160 }
2161 else if ( CMIS_TYPE_BOOL == sType )
2162 {
2163 Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2164 sal_Int32 k = 0;
2165 for ( const auto& rxYesNo : pLine->m_aYesNos )
2166 {
2167 bool bValue = rxYesNo->m_xYesButton->get_active();
2168 seqValue[k] = bValue;
2169 ++k;
2170 }
2171 aPropertiesSeq[i].Value <<= seqValue;
2172
2173 }
2174 else if ( CMIS_TYPE_DATETIME == sType )
2175 {
2176 Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2177 sal_Int32 k = 0;
2178 for ( const auto& rxDateTime : pLine->m_aDateTimes )
2179 {
2180 Date aTmpDate = rxDateTime->m_xDateField->get_date();
2181 tools::Time aTmpTime = rxDateTime->m_xTimeField->get_value();
2182 util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2183 aTmpTime.GetMin(), aTmpTime.GetHour(),
2184 aTmpDate.GetDay(), aTmpDate.GetMonth(),
2185 aTmpDate.GetYear(), true );
2186 seqValue[k] = aDateTime;
2187 ++k;
2188 }
2189 aPropertiesSeq[i].Value <<= seqValue;
2190 }
2191 else
2192 {
2193 Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2194 sal_Int32 k = 0;
2195 for ( const auto& rxValue : pLine->m_aValues )
2196 {
2197 OUString sValue( rxValue->m_xValueEdit->get_text() );
2198 seqValue[k] = sValue;
2199 ++k;
2200 }
2201 aPropertiesSeq[i].Value <<= seqValue;
2202 }
2203 }
2204 ++i;
2205 }
2206
2207 return aPropertiesSeq;
2208 }
2209
CmisPropertiesControl(weld::Builder & rBuilder)2210 CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2211 : m_aPropertiesWin(rBuilder.weld_container("CmisWindow"))
2212 , m_xScrolledWindow(rBuilder.weld_scrolled_window("CmisScroll"))
2213 {
2214 // set height to something small and force it to take the size
2215 // dictated by the other pages
2216 m_xScrolledWindow->set_size_request(-1, 42);
2217 }
2218
ClearAllLines()2219 void CmisPropertiesControl::ClearAllLines()
2220 {
2221 m_aPropertiesWin.ClearAllLines();
2222 }
2223
AddLine(const OUString & sId,const OUString & sName,const OUString & sType,const bool bUpdatable,const bool bRequired,const bool bMultiValued,const bool bOpenChoice,Any & aChoices,Any const & rAny)2224 void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2225 const OUString& sType, const bool bUpdatable,
2226 const bool bRequired, const bool bMultiValued,
2227 const bool bOpenChoice, Any& aChoices, Any const & rAny
2228 )
2229 {
2230 m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2231 bOpenChoice, aChoices, rAny );
2232 }
2233
2234 // class SfxCmisPropertiesPage -----------------------------------------
SfxCmisPropertiesPage(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet & rItemSet)2235 SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2236 : SfxTabPage(pPage, pController, "sfx/ui/cmisinfopage.ui", "CmisInfoPage", &rItemSet)
2237 , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2238 {
2239 }
2240
~SfxCmisPropertiesPage()2241 SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2242 {
2243 m_xPropertiesCtrl.reset();
2244 }
2245
FillItemSet(SfxItemSet * rSet)2246 bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2247 {
2248 const SfxPoolItem* pItem = nullptr;
2249 SfxDocumentInfoItem* pInfo = nullptr;
2250 bool bMustDelete = false;
2251
2252 if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2253 {
2254 if (SfxItemState::SET != pItemSet->GetItemState(SID_DOCINFO, true, &pItem))
2255 pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2256 else
2257 {
2258 bMustDelete = true;
2259 pInfo = new SfxDocumentInfoItem( *static_cast<const SfxDocumentInfoItem*>(pItem) );
2260 }
2261 }
2262
2263 sal_Int32 modifiedNum = 0;
2264 if ( pInfo )
2265 {
2266 Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2267 Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2268
2269 std::vector< document::CmisProperty > changedProps;
2270 for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2271 {
2272 if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2273 {
2274 if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2275 {
2276 Sequence< util::DateTime > oldValue;
2277 aOldProps[i].Value >>= oldValue;
2278 // We only edit hours and minutes
2279 // don't compare NanoSeconds and Seconds
2280 for ( auto& rDateTime : oldValue )
2281 {
2282 rDateTime.NanoSeconds = 0;
2283 rDateTime.Seconds = 0;
2284 }
2285 Sequence< util::DateTime > newValue;
2286 aNewProps[i].Value >>= newValue;
2287 if ( oldValue != newValue )
2288 {
2289 modifiedNum++;
2290 changedProps.push_back( aNewProps[i] );
2291 }
2292 }
2293 else if ( aOldProps[i].Value != aNewProps[i].Value )
2294 {
2295 modifiedNum++;
2296 changedProps.push_back( aNewProps[i] );
2297 }
2298 }
2299 }
2300 Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2301 pInfo->SetCmisProperties( aModifiedProps );
2302 rSet->Put( *pInfo );
2303 if ( bMustDelete )
2304 delete pInfo;
2305 }
2306
2307 return modifiedNum;
2308 }
2309
Reset(const SfxItemSet * rItemSet)2310 void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2311 {
2312 m_xPropertiesCtrl->ClearAllLines();
2313 const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2314 uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2315 for ( auto& rCmisProp : aCmisProps )
2316 {
2317 m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2318 rCmisProp.Name,
2319 rCmisProp.Type,
2320 rCmisProp.Updatable,
2321 rCmisProp.Required,
2322 rCmisProp.MultiValued,
2323 rCmisProp.OpenChoice,
2324 rCmisProp.Choices,
2325 rCmisProp.Value);
2326 }
2327 }
2328
DeactivatePage(SfxItemSet *)2329 DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2330 {
2331 return DeactivateRC::LeavePage;
2332 }
2333
Create(weld::Container * pPage,weld::DialogController * pController,const SfxItemSet * rItemSet)2334 std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2335 {
2336 return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2337 }
2338
2339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
2340