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