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 <com/sun/star/ui/dialogs/XExecutableDialog.hpp> 21 #include <com/sun/star/ui/dialogs/XFilePicker.hpp> 22 #include <com/sun/star/ui/dialogs/XFilePickerControlAccess.hpp> 23 #include <com/sun/star/ui/dialogs/CommonFilePickerElementIds.hpp> 24 #include <com/sun/star/ui/dialogs/ExtendedFilePickerElementIds.hpp> 25 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp> 26 #include <com/sun/star/view/XSelectionSupplier.hpp> 27 #include <com/sun/star/beans/PropertyExistException.hpp> 28 #include <com/sun/star/beans/XPropertyAccess.hpp> 29 #include <com/sun/star/beans/XPropertySet.hpp> 30 #include <com/sun/star/beans/XPropertyContainer.hpp> 31 #include <com/sun/star/beans/PropertyAttribute.hpp> 32 #include <com/sun/star/document/XExporter.hpp> 33 #include <com/sun/star/document/XDocumentPropertiesSupplier.hpp> 34 #include <com/sun/star/document/XDocumentProperties.hpp> 35 #include <com/sun/star/task/ErrorCodeIOException.hpp> 36 #include <com/sun/star/task/InteractionHandler.hpp> 37 #include <com/sun/star/util/DateTime.hpp> 38 #include <com/sun/star/util/URLTransformer.hpp> 39 #include <com/sun/star/util/XURLTransformer.hpp> 40 #include <com/sun/star/frame/ModuleManager.hpp> 41 #include <com/sun/star/frame/XStorable.hpp> 42 #include <com/sun/star/frame/XStorable2.hpp> 43 #include <com/sun/star/frame/XDispatchProvider.hpp> 44 #include <com/sun/star/frame/XDispatch.hpp> 45 #include <com/sun/star/frame/XTitle.hpp> 46 #include <com/sun/star/util/XModifyListener.hpp> 47 #include <com/sun/star/util/XModifiable.hpp> 48 #include <com/sun/star/util/XModifyBroadcaster.hpp> 49 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 50 51 #include <com/sun/star/util/XCloneable.hpp> 52 #include <com/sun/star/io/IOException.hpp> 53 54 #include <guisaveas.hxx> 55 56 #include <sal/log.hxx> 57 #include <unotools/pathoptions.hxx> 58 #include <svl/itemset.hxx> 59 #include <svl/eitem.hxx> 60 #include <svl/stritem.hxx> 61 #include <svl/intitem.hxx> 62 #include <unotools/useroptions.hxx> 63 #include <unotools/saveopt.hxx> 64 #include <svtools/miscopt.hxx> 65 #include <tools/debug.hxx> 66 #include <tools/urlobj.hxx> 67 #include <comphelper/processfactory.hxx> 68 #include <comphelper/propertysequence.hxx> 69 #include <comphelper/sequenceashashmap.hxx> 70 #include <comphelper/mimeconfighelper.hxx> 71 #include <comphelper/lok.hxx> 72 #include <vcl/weld.hxx> 73 #include <vcl/window.hxx> 74 #include <toolkit/awt/vclxwindow.hxx> 75 #include <o3tl/char16_t2wchar_t.hxx> 76 77 #include <sfx2/sfxsids.hrc> 78 #include <sfx2/strings.hrc> 79 #include <sfx2/sfxresid.hxx> 80 #include <sfx2/docfilt.hxx> 81 #include <sfx2/filedlghelper.hxx> 82 #include <sfx2/asyncfunc.hxx> 83 #include <sfx2/app.hxx> 84 #include <sfx2/objsh.hxx> 85 #include <sfx2/request.hxx> 86 #include <sfx2/sfxuno.hxx> 87 #include <sfxtypes.hxx> 88 #include <alienwarn.hxx> 89 90 #include <sfx2/docmacromode.hxx> 91 #include <com/sun/star/task/ErrorCodeRequest.hpp> 92 #include <rtl/ref.hxx> 93 #include <framework/interaction.hxx> 94 #include <svtools/sfxecode.hxx> 95 96 #include <memory> 97 98 #include <com/sun/star/frame/Desktop.hpp> 99 100 #include <officecfg/Office/Common.hxx> 101 102 #include <vcl/FilterConfigItem.hxx> 103 #include <com/sun/star/system/SystemShellExecute.hpp> 104 #include <com/sun/star/system/SystemShellExecuteFlags.hpp> 105 106 #include <osl/file.hxx> 107 108 #ifdef _WIN32 109 #include <Shlobj.h> 110 #ifdef GetTempPath 111 #undef GetTempPath 112 #endif 113 #endif 114 115 // flags that specify requested operation 116 #define EXPORT_REQUESTED 1 117 #define PDFEXPORT_REQUESTED 2 118 #define PDFDIRECTEXPORT_REQUESTED 4 119 #define WIDEEXPORT_REQUESTED 8 120 #define SAVE_REQUESTED 16 121 #define SAVEAS_REQUESTED 32 122 #define SAVEACOPY_REQUESTED 64 123 #define EPUBEXPORT_REQUESTED 128 124 #define EPUBDIRECTEXPORT_REQUESTED 256 125 #define SAVEASREMOTE_REQUESTED -1 126 127 // possible statuses of save operation 128 #define STATUS_NO_ACTION 0 129 #define STATUS_SAVE 1 130 #define STATUS_SAVEAS 2 131 #define STATUS_SAVEAS_STANDARDNAME 3 132 133 const char aFilterNameString[] = "FilterName"; 134 const char aFilterOptionsString[] = "FilterOptions"; 135 const char aFilterDataString[] = "FilterData"; 136 137 using namespace ::com::sun::star; 138 using namespace css::system; 139 140 namespace { 141 142 sal_uInt16 getSlotIDFromMode( sal_Int16 nStoreMode ) 143 { 144 // This is a temporary hardcoded solution must be removed when 145 // dialogs do not need parameters in SidSet representation any more 146 147 sal_uInt16 nResult = 0; 148 if ( nStoreMode == EXPORT_REQUESTED || nStoreMode == ( EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED ) ) 149 nResult = SID_EXPORTDOC; 150 else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED ) ) 151 nResult = SID_EXPORTDOCASPDF; 152 else if ( nStoreMode == ( EXPORT_REQUESTED | EPUBEXPORT_REQUESTED ) ) 153 nResult = SID_EXPORTDOCASEPUB; 154 else if ( nStoreMode == ( EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED ) ) 155 nResult = SID_DIRECTEXPORTDOCASPDF; 156 else if ( nStoreMode == ( EXPORT_REQUESTED | EPUBEXPORT_REQUESTED | EPUBDIRECTEXPORT_REQUESTED ) ) 157 nResult = SID_DIRECTEXPORTDOCASEPUB; 158 else if ( nStoreMode == SAVEAS_REQUESTED || nStoreMode == ( EXPORT_REQUESTED | WIDEEXPORT_REQUESTED ) ) 159 nResult = SID_SAVEASDOC; 160 else if ( nStoreMode == SAVEASREMOTE_REQUESTED ) 161 nResult = SID_SAVEASREMOTE; 162 else { 163 SAL_WARN( "sfx.doc", "Unacceptable slot name is provided!" ); 164 } 165 166 return nResult; 167 } 168 169 170 sal_Int16 getStoreModeFromSlotName( const OUString& aSlotName ) 171 { 172 sal_Int16 nResult = 0; 173 if ( aSlotName == "ExportTo" ) 174 nResult = EXPORT_REQUESTED; 175 else if ( aSlotName == "ExportToPDF" ) 176 nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED; 177 else if ( aSlotName == "ExportDirectToPDF" ) 178 nResult = EXPORT_REQUESTED | PDFEXPORT_REQUESTED | PDFDIRECTEXPORT_REQUESTED; 179 else if ( aSlotName == "ExportToEPUB" ) 180 nResult = EXPORT_REQUESTED | EPUBEXPORT_REQUESTED; 181 else if ( aSlotName == "ExportDirectToEPUB" ) 182 nResult = EXPORT_REQUESTED | EPUBEXPORT_REQUESTED | EPUBDIRECTEXPORT_REQUESTED; 183 else if ( aSlotName == "Save" ) 184 nResult = SAVE_REQUESTED; 185 else if ( aSlotName == "SaveAs" ) 186 nResult = SAVEAS_REQUESTED; 187 else if ( aSlotName == "SaveAsRemote" ) 188 nResult = SAVEASREMOTE_REQUESTED; 189 else 190 throw task::ErrorCodeIOException( 191 ("getStoreModeFromSlotName(\"" + aSlotName 192 + "): ERRCODE_IO_INVALIDPARAMETER"), 193 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER) ); 194 195 return nResult; 196 } 197 198 199 SfxFilterFlags getMustFlags( sal_Int16 nStoreMode ) 200 { 201 return ( SfxFilterFlags::EXPORT 202 | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? SfxFilterFlags::NONE : SfxFilterFlags::IMPORT ) ); 203 } 204 205 206 SfxFilterFlags getDontFlags( sal_Int16 nStoreMode ) 207 { 208 return ( SfxFilterFlags::INTERNAL 209 | SfxFilterFlags::NOTINFILEDLG 210 | ( ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) ? SfxFilterFlags::IMPORT : SfxFilterFlags::NONE ) ); 211 } 212 213 214 // class DocumentSettingsGuard 215 216 217 class DocumentSettingsGuard 218 { 219 uno::Reference< beans::XPropertySet > m_xDocumentSettings; 220 bool m_bPreserveReadOnly; 221 bool m_bReadOnlySupported; 222 223 bool const m_bRestoreSettings; 224 public: 225 DocumentSettingsGuard( const uno::Reference< frame::XModel >& xModel, bool bReadOnly, bool bRestore ) 226 : m_bPreserveReadOnly( false ) 227 , m_bReadOnlySupported( false ) 228 , m_bRestoreSettings( bRestore ) 229 { 230 try 231 { 232 uno::Reference< lang::XMultiServiceFactory > xDocSettingsSupplier( xModel, uno::UNO_QUERY_THROW ); 233 m_xDocumentSettings.set( 234 xDocSettingsSupplier->createInstance( "com.sun.star.document.Settings" ), 235 uno::UNO_QUERY_THROW ); 236 237 OUString aLoadReadonlyString( "LoadReadonly" ); 238 239 try 240 { 241 m_xDocumentSettings->getPropertyValue( aLoadReadonlyString ) >>= m_bPreserveReadOnly; 242 m_xDocumentSettings->setPropertyValue( aLoadReadonlyString, uno::makeAny( bReadOnly ) ); 243 m_bReadOnlySupported = true; 244 } 245 catch( const uno::Exception& ) 246 {} 247 } 248 catch( const uno::Exception& ) 249 {} 250 251 if ( bReadOnly && !m_bReadOnlySupported ) 252 throw uno::RuntimeException(); // the user could provide the data, so it must be stored 253 } 254 255 ~DocumentSettingsGuard() 256 { 257 if ( m_bRestoreSettings ) 258 { 259 try 260 { 261 if ( m_bReadOnlySupported ) 262 m_xDocumentSettings->setPropertyValue( "LoadReadonly", uno::makeAny( m_bPreserveReadOnly ) ); 263 } 264 catch( const uno::Exception& ) 265 { 266 OSL_FAIL( "Unexpected exception!" ); 267 } 268 } 269 } 270 }; 271 } // anonymous namespace 272 273 274 // class ModelData_Impl 275 276 class ModelData_Impl 277 { 278 SfxStoringHelper* m_pOwner; 279 uno::Reference< frame::XModel > m_xModel; 280 uno::Reference< frame::XStorable > m_xStorable; 281 uno::Reference< frame::XStorable2 > m_xStorable2; 282 283 OUString m_aModuleName; 284 std::unique_ptr<::comphelper::SequenceAsHashMap> m_pDocumentPropsHM; 285 std::unique_ptr<::comphelper::SequenceAsHashMap> m_pModulePropsHM; 286 287 ::comphelper::SequenceAsHashMap m_aMediaDescrHM; 288 289 bool m_bRecommendReadOnly; 290 291 public: 292 ModelData_Impl( SfxStoringHelper& aOwner, 293 const uno::Reference< frame::XModel >& xModel, 294 const uno::Sequence< beans::PropertyValue >& aMediaDescr ); 295 296 ~ModelData_Impl(); 297 298 void FreeDocumentProps(); 299 300 uno::Reference< frame::XModel > const & GetModel(); 301 uno::Reference< frame::XStorable > const & GetStorable(); 302 uno::Reference< frame::XStorable2 > const & GetStorable2(); 303 304 ::comphelper::SequenceAsHashMap& GetMediaDescr() { return m_aMediaDescrHM; } 305 306 bool IsRecommendReadOnly() const { return m_bRecommendReadOnly; } 307 308 const ::comphelper::SequenceAsHashMap& GetDocProps(); 309 310 OUString const & GetModuleName(); 311 const ::comphelper::SequenceAsHashMap& GetModuleProps(); 312 313 void CheckInteractionHandler(); 314 315 316 OUString GetDocServiceName(); 317 uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust, SfxFilterFlags nDont ); 318 uno::Sequence< beans::PropertyValue > GetDocServiceAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ); 319 uno::Sequence< beans::PropertyValue > GetPreselectedFilter_Impl( sal_Int16 nStoreMode ); 320 uno::Sequence< beans::PropertyValue > GetDocServiceDefaultFilter(); 321 322 bool ExecuteFilterDialog_Impl( const OUString& aFilterName ); 323 324 sal_Int8 CheckSaveAcceptable( sal_Int8 nCurStatus ); 325 sal_Int8 CheckStateForSave(); 326 327 sal_Int8 CheckFilter( const OUString& ); 328 329 bool CheckFilterOptionsDialogExistence(); 330 331 bool OutputFileDialog( sal_Int16 nStoreMode, 332 const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM, 333 bool bSetStandardName, 334 OUString& aSuggestedName, 335 bool bPreselectPassword, 336 OUString& aSuggestedDir, 337 sal_Int16 nDialog, 338 const OUString& rStandardDir, 339 const css::uno::Sequence< OUString >& rBlackList 340 ); 341 342 bool ShowDocumentInfoDialog(const std::function< void () >&); 343 344 static OUString GetRecommendedExtension( const OUString& aTypeName ); 345 OUString GetRecommendedDir( const OUString& aSuggestedDir ); 346 OUString GetRecommendedName( const OUString& aSuggestedName, 347 const OUString& aTypeName ); 348 349 }; 350 351 352 ModelData_Impl::ModelData_Impl( SfxStoringHelper& aOwner, 353 const uno::Reference< frame::XModel >& xModel, 354 const uno::Sequence< beans::PropertyValue >& aMediaDescr ) 355 : m_pOwner( &aOwner ) 356 , m_xModel( xModel ) 357 , m_aMediaDescrHM( aMediaDescr ) 358 , m_bRecommendReadOnly( false ) 359 { 360 CheckInteractionHandler(); 361 } 362 363 364 ModelData_Impl::~ModelData_Impl() 365 { 366 FreeDocumentProps(); 367 m_pDocumentPropsHM.reset(); 368 m_pModulePropsHM.reset(); 369 } 370 371 372 void ModelData_Impl::FreeDocumentProps() 373 { 374 m_pDocumentPropsHM.reset(); 375 } 376 377 378 uno::Reference< frame::XModel > const & ModelData_Impl::GetModel() 379 { 380 if ( !m_xModel.is() ) 381 throw uno::RuntimeException(); 382 383 return m_xModel; 384 } 385 386 387 uno::Reference< frame::XStorable > const & ModelData_Impl::GetStorable() 388 { 389 if ( !m_xStorable.is() ) 390 { 391 m_xStorable.set( m_xModel, uno::UNO_QUERY_THROW ); 392 } 393 394 return m_xStorable; 395 } 396 397 398 uno::Reference< frame::XStorable2 > const & ModelData_Impl::GetStorable2() 399 { 400 if ( !m_xStorable2.is() ) 401 { 402 m_xStorable2.set( m_xModel, uno::UNO_QUERY_THROW ); 403 } 404 405 return m_xStorable2; 406 } 407 408 409 const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetDocProps() 410 { 411 if ( !m_pDocumentPropsHM ) 412 m_pDocumentPropsHM.reset( new ::comphelper::SequenceAsHashMap( GetModel()->getArgs() ) ); 413 414 return *m_pDocumentPropsHM; 415 } 416 417 418 OUString const & ModelData_Impl::GetModuleName() 419 { 420 if ( m_aModuleName.isEmpty() ) 421 { 422 m_aModuleName = m_pOwner->GetModuleManager()->identify( 423 uno::Reference< uno::XInterface >( m_xModel, uno::UNO_QUERY ) ); 424 if ( m_aModuleName.isEmpty() ) 425 throw uno::RuntimeException(); // TODO: 426 } 427 return m_aModuleName; 428 } 429 430 431 const ::comphelper::SequenceAsHashMap& ModelData_Impl::GetModuleProps() 432 { 433 if ( !m_pModulePropsHM ) 434 { 435 uno::Sequence< beans::PropertyValue > aModuleProps; 436 m_pOwner->GetModuleManager()->getByName( GetModuleName() ) >>= aModuleProps; 437 if ( !aModuleProps.hasElements() ) 438 throw uno::RuntimeException(); // TODO; 439 m_pModulePropsHM.reset( new ::comphelper::SequenceAsHashMap( aModuleProps ) ); 440 } 441 442 return *m_pModulePropsHM; 443 } 444 445 446 OUString ModelData_Impl::GetDocServiceName() 447 { 448 return GetModuleProps().getUnpackedValueOrDefault("ooSetupFactoryDocumentService", OUString()); 449 } 450 451 452 void ModelData_Impl::CheckInteractionHandler() 453 { 454 const OUString sInteractionHandler {"InteractionHandler"}; 455 ::comphelper::SequenceAsHashMap::const_iterator aInteractIter = 456 m_aMediaDescrHM.find( sInteractionHandler ); 457 458 if ( aInteractIter == m_aMediaDescrHM.end() ) 459 { 460 try { 461 m_aMediaDescrHM[ sInteractionHandler ] 462 <<= task::InteractionHandler::createWithParent( comphelper::getProcessComponentContext(), nullptr); 463 } 464 catch( const uno::Exception& ) 465 { 466 } 467 } 468 else 469 { 470 uno::Reference< task::XInteractionHandler > xInteract; 471 DBG_ASSERT( ( aInteractIter->second >>= xInteract ) && xInteract.is(), "Broken interaction handler is provided!\n" ); 472 } 473 } 474 475 476 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilter() 477 { 478 uno::Sequence< beans::PropertyValue > aProps; 479 480 const OUString aFilterName = GetModuleProps().getUnpackedValueOrDefault( "ooSetupFactoryDefaultFilter", OUString() ); 481 482 m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aProps; 483 484 return aProps; 485 } 486 487 488 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags nMust, 489 SfxFilterFlags nDont ) 490 { 491 uno::Sequence< beans::PropertyValue > aFilterProps; 492 uno::Sequence< beans::PropertyValue > aProps = GetDocServiceDefaultFilter(); 493 if ( aProps.hasElements() ) 494 { 495 ::comphelper::SequenceAsHashMap aFiltHM( aProps ); 496 SfxFilterFlags nFlags = static_cast<SfxFilterFlags>(aFiltHM.getUnpackedValueOrDefault("Flags", 497 sal_Int32(0) )); 498 if ( ( ( nFlags & nMust ) == nMust ) && !( nFlags & nDont ) ) 499 aFilterProps = aProps; 500 } 501 502 return aFilterProps; 503 } 504 505 506 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetDocServiceAnyFilter( SfxFilterFlags nMust, SfxFilterFlags nDont ) 507 { 508 uno::Sequence< beans::NamedValue > aSearchRequest { { "DocumentService", css::uno::makeAny(GetDocServiceName()) } }; 509 510 return ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont ); 511 } 512 513 514 uno::Sequence< beans::PropertyValue > ModelData_Impl::GetPreselectedFilter_Impl( sal_Int16 nStoreMode ) 515 { 516 if ( nStoreMode == SAVEASREMOTE_REQUESTED ) 517 nStoreMode = SAVEAS_REQUESTED; 518 519 uno::Sequence< beans::PropertyValue > aFilterProps; 520 521 SfxFilterFlags nMust = getMustFlags( nStoreMode ); 522 SfxFilterFlags nDont = getDontFlags( nStoreMode ); 523 524 if ( ( nStoreMode != SAVEASREMOTE_REQUESTED ) && ( nStoreMode & PDFEXPORT_REQUESTED ) ) 525 { 526 // Preselect PDF-Filter for EXPORT 527 uno::Sequence< beans::NamedValue > aSearchRequest 528 { 529 { "Type", css::uno::makeAny(OUString("pdf_Portable_Document_Format")) }, 530 { "DocumentService", css::uno::makeAny(GetDocServiceName()) } 531 }; 532 533 aFilterProps = ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont ); 534 } 535 else if ( ( nStoreMode != SAVEASREMOTE_REQUESTED ) && ( nStoreMode & EPUBEXPORT_REQUESTED ) ) 536 { 537 // Preselect EPUB filter for export. 538 uno::Sequence<beans::NamedValue> aSearchRequest 539 { 540 { "Type", css::uno::makeAny(OUString("writer_EPUB_Document")) }, 541 { "DocumentService", css::uno::makeAny(GetDocServiceName()) } 542 }; 543 544 aFilterProps = ::comphelper::MimeConfigurationHelper::SearchForFilter( m_pOwner->GetFilterQuery(), aSearchRequest, nMust, nDont ); 545 } 546 else 547 { 548 aFilterProps = GetDocServiceDefaultFilterCheckFlags( nMust, nDont ); 549 550 if ( !aFilterProps.hasElements() ) 551 { 552 // the default filter was not found, use just the first acceptable one 553 aFilterProps = GetDocServiceAnyFilter( nMust, nDont ); 554 } 555 } 556 557 return aFilterProps; 558 } 559 560 561 bool ModelData_Impl::ExecuteFilterDialog_Impl( const OUString& aFilterName ) 562 { 563 bool bDialogUsed = false; 564 565 try { 566 uno::Sequence < beans::PropertyValue > aProps; 567 uno::Any aAny = m_pOwner->GetFilterConfiguration()->getByName( aFilterName ); 568 if ( aAny >>= aProps ) 569 { 570 const sal_Int32 nPropertyCount = aProps.getLength(); 571 for( sal_Int32 nProperty=0; nProperty < nPropertyCount; ++nProperty ) 572 { 573 if( aProps[nProperty].Name == "UIComponent" ) 574 { 575 OUString aServiceName; 576 aProps[nProperty].Value >>= aServiceName; 577 if( !aServiceName.isEmpty() ) 578 { 579 uno::Sequence<uno::Any> aDialogArgs(comphelper::InitAnyPropertySequence( 580 { 581 {"ParentWindow", uno::Any(SfxStoringHelper::GetModelXWindow(m_xModel))}, 582 })); 583 584 uno::Reference< ui::dialogs::XExecutableDialog > xFilterDialog( 585 comphelper::getProcessServiceFactory()->createInstanceWithArguments(aServiceName, aDialogArgs), uno::UNO_QUERY ); 586 uno::Reference< beans::XPropertyAccess > xFilterProperties( xFilterDialog, uno::UNO_QUERY ); 587 588 if( xFilterDialog.is() && xFilterProperties.is() ) 589 { 590 bDialogUsed = true; 591 592 uno::Reference< document::XExporter > xExporter( xFilterDialog, uno::UNO_QUERY ); 593 if( xExporter.is() ) 594 xExporter->setSourceDocument( 595 uno::Reference< lang::XComponent >( GetModel(), uno::UNO_QUERY ) ); 596 597 uno::Sequence< beans::PropertyValue > aPropsForDialog; 598 GetMediaDescr() >> aPropsForDialog; 599 xFilterProperties->setPropertyValues( aPropsForDialog ); 600 601 if( !xFilterDialog->execute() ) 602 { 603 throw task::ErrorCodeIOException( 604 ("ModelData_Impl::ExecuteFilterDialog_Impl:" 605 " ERRCODE_IO_ABORT"), 606 uno::Reference< uno::XInterface >(), 607 sal_uInt32(ERRCODE_IO_ABORT)); 608 } 609 610 uno::Sequence< beans::PropertyValue > aPropsFromDialog = 611 xFilterProperties->getPropertyValues(); 612 const sal_Int32 nPropsLen {aPropsFromDialog.getLength()}; 613 for ( sal_Int32 nInd = 0; nInd < nPropsLen; ++nInd ) 614 GetMediaDescr()[aPropsFromDialog[nInd].Name] = aPropsFromDialog[nInd].Value; 615 } 616 } 617 618 break; 619 } 620 } 621 } 622 } 623 catch( const container::NoSuchElementException& e ) 624 { 625 // the filter name is unknown 626 throw task::ErrorCodeIOException( 627 ("ModelData_Impl::ExecuteFilterDialog_Impl: NoSuchElementException" 628 " \"" + e.Message + "\": ERRCODE_IO_ABORT"), 629 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER)); 630 } 631 catch( const task::ErrorCodeIOException& ) 632 { 633 throw; 634 } 635 catch( const uno::Exception& e ) 636 { 637 SAL_WARN("sfx.doc", "ignoring " << e); 638 } 639 640 return bDialogUsed; 641 } 642 643 644 sal_Int8 ModelData_Impl::CheckSaveAcceptable( sal_Int8 nCurStatus ) 645 { 646 sal_Int8 nResult = nCurStatus; 647 648 if ( nResult != STATUS_NO_ACTION && GetStorable()->hasLocation() ) 649 { 650 // the saving is acceptable 651 // in case the configuration entry is not set or set to false 652 // or in case of version creation 653 if ( officecfg::Office::Common::Save::Document::AlwaysSaveAs::get() 654 && GetMediaDescr().find( OUString("VersionComment") ) == GetMediaDescr().end() ) 655 { 656 // notify the user that SaveAs is going to be done 657 vcl::Window* pWin = SfxStoringHelper::GetModelWindow(m_xModel); 658 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, 659 VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_NEW_FILENAME_SAVE))); 660 if (xMessageBox->run() == RET_OK) 661 nResult = STATUS_SAVEAS; 662 else 663 nResult = STATUS_NO_ACTION; 664 } 665 } 666 667 return nResult; 668 } 669 670 671 sal_Int8 ModelData_Impl::CheckStateForSave() 672 { 673 // if the document is readonly or a new one a SaveAs operation must be used 674 if ( !GetStorable()->hasLocation() || GetStorable()->isReadonly() ) 675 return STATUS_SAVEAS; 676 677 // check acceptable entries for media descriptor 678 ::comphelper::SequenceAsHashMap aAcceptedArgs; 679 680 const OUString aVersionCommentString("VersionComment"); 681 const OUString aAuthorString("Author"); 682 const OUString aDontTerminateEdit("DontTerminateEdit"); 683 const OUString aInteractionHandlerString("InteractionHandler"); 684 const OUString aStatusIndicatorString("StatusIndicator"); 685 const OUString aFailOnWarningString("FailOnWarning"); 686 const OUString aNoFileSync("NoFileSync"); 687 688 if ( GetMediaDescr().find( aVersionCommentString ) != GetMediaDescr().end() ) 689 aAcceptedArgs[ aVersionCommentString ] = GetMediaDescr()[ aVersionCommentString ]; 690 if ( GetMediaDescr().find( aAuthorString ) != GetMediaDescr().end() ) 691 aAcceptedArgs[ aAuthorString ] = GetMediaDescr()[ aAuthorString ]; 692 if ( GetMediaDescr().find( aDontTerminateEdit ) != GetMediaDescr().end() ) 693 aAcceptedArgs[ aDontTerminateEdit ] = GetMediaDescr()[ aDontTerminateEdit ]; 694 if ( GetMediaDescr().find( aInteractionHandlerString ) != GetMediaDescr().end() ) 695 aAcceptedArgs[ aInteractionHandlerString ] = GetMediaDescr()[ aInteractionHandlerString ]; 696 if ( GetMediaDescr().find( aStatusIndicatorString ) != GetMediaDescr().end() ) 697 aAcceptedArgs[ aStatusIndicatorString ] = GetMediaDescr()[ aStatusIndicatorString ]; 698 if ( GetMediaDescr().find( aFailOnWarningString ) != GetMediaDescr().end() ) 699 aAcceptedArgs[ aFailOnWarningString ] = GetMediaDescr()[ aFailOnWarningString ]; 700 if (GetMediaDescr().find(aNoFileSync) != GetMediaDescr().end()) 701 aAcceptedArgs[aNoFileSync] = GetMediaDescr()[aNoFileSync]; 702 703 // remove unacceptable entry if there is any 704 DBG_ASSERT( GetMediaDescr().size() == aAcceptedArgs.size(), 705 "Unacceptable parameters are provided in Save request!\n" ); 706 if ( GetMediaDescr().size() != aAcceptedArgs.size() ) 707 GetMediaDescr() = aAcceptedArgs; 708 709 // check that the old filter is acceptable 710 return CheckFilter( GetDocProps().getUnpackedValueOrDefault(aFilterNameString, OUString()) ); 711 } 712 713 sal_Int8 ModelData_Impl::CheckFilter( const OUString& aFilterName ) 714 { 715 ::comphelper::SequenceAsHashMap aFiltPropsHM; 716 SfxFilterFlags nFiltFlags = SfxFilterFlags::NONE; 717 if ( !aFilterName.isEmpty() ) 718 { 719 // get properties of filter 720 uno::Sequence< beans::PropertyValue > aFilterProps; 721 m_pOwner->GetFilterConfiguration()->getByName( aFilterName ) >>= aFilterProps; 722 723 aFiltPropsHM = ::comphelper::SequenceAsHashMap( aFilterProps ); 724 nFiltFlags = static_cast<SfxFilterFlags>(aFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) )); 725 } 726 727 // only a temporary solution until default filter retrieving feature is implemented 728 // then GetDocServiceDefaultFilter() must be used 729 ::comphelper::SequenceAsHashMap aDefFiltPropsHM = GetDocServiceDefaultFilterCheckFlags( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT, SfxFilterFlags::NONE ); 730 SfxFilterFlags nDefFiltFlags = static_cast<SfxFilterFlags>(aDefFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) )); 731 732 // if the old filter is not acceptable 733 // and there is no default filter or it is not acceptable for requested parameters then proceed with saveAs 734 if ( ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) ) 735 && ( aDefFiltPropsHM.empty() || !( nDefFiltFlags & SfxFilterFlags::EXPORT ) || nDefFiltFlags & SfxFilterFlags::INTERNAL ) ) 736 return STATUS_SAVEAS; 737 738 // so at this point there is either an acceptable old filter or default one 739 if ( aFiltPropsHM.empty() || !( nFiltFlags & SfxFilterFlags::EXPORT ) ) 740 { 741 // so the default filter must be acceptable 742 return STATUS_SAVEAS_STANDARDNAME; 743 } 744 else if ( ( !( nFiltFlags & SfxFilterFlags::OWN ) || ( nFiltFlags & SfxFilterFlags::ALIEN ) ) 745 && !aDefFiltPropsHM.empty() 746 && ( nDefFiltFlags & SfxFilterFlags::EXPORT ) && !( nDefFiltFlags & SfxFilterFlags::INTERNAL )) 747 { 748 // the default filter is acceptable and the old filter is alien one 749 // so ask to make a saveAs operation 750 const OUString aUIName = aFiltPropsHM.getUnpackedValueOrDefault("UIName", OUString() ); 751 const OUString aDefUIName = aDefFiltPropsHM.getUnpackedValueOrDefault("UIName", OUString() ); 752 const OUString aPreusedFilterName = GetDocProps().getUnpackedValueOrDefault("PreusedFilterName", OUString() ); 753 const OUString aDefType = aDefFiltPropsHM.getUnpackedValueOrDefault( "Type", OUString() ); 754 const OUString aDefExtension = GetRecommendedExtension( aDefType ); 755 756 if ( aPreusedFilterName != aFilterName && aUIName != aDefUIName ) 757 { 758 if ( !SfxStoringHelper::WarnUnacceptableFormat( GetModel(), aUIName, aDefExtension, 759 static_cast<bool>( nDefFiltFlags & SfxFilterFlags::ALIEN ) ) ) 760 return STATUS_SAVEAS_STANDARDNAME; 761 } 762 } 763 764 return STATUS_SAVE; 765 } 766 767 768 bool ModelData_Impl::CheckFilterOptionsDialogExistence() 769 { 770 uno::Sequence< beans::NamedValue > aSearchRequest { { "DocumentService", css::uno::makeAny(GetDocServiceName()) } }; 771 772 uno::Reference< container::XEnumeration > xFilterEnum = 773 m_pOwner->GetFilterQuery()->createSubSetEnumerationByProperties( aSearchRequest ); 774 775 while ( xFilterEnum->hasMoreElements() ) 776 { 777 uno::Sequence< beans::PropertyValue > aProps; 778 if ( xFilterEnum->nextElement() >>= aProps ) 779 { 780 ::comphelper::SequenceAsHashMap aPropsHM( aProps ); 781 if ( !aPropsHM.getUnpackedValueOrDefault("UIComponent", OUString()).isEmpty() ) 782 return true; 783 } 784 } 785 786 return false; 787 } 788 789 790 bool ModelData_Impl::OutputFileDialog( sal_Int16 nStoreMode, 791 const ::comphelper::SequenceAsHashMap& aPreselectedFilterPropsHM, 792 bool bSetStandardName, 793 OUString& aSuggestedName, 794 bool bPreselectPassword, 795 OUString& aSuggestedDir, 796 sal_Int16 nDialog, 797 const OUString& rStandardDir, 798 const css::uno::Sequence< OUString >& rBlackList) 799 { 800 if ( nStoreMode == SAVEASREMOTE_REQUESTED ) 801 nStoreMode = SAVEAS_REQUESTED; 802 803 bool bUseFilterOptions = false; 804 805 ::comphelper::SequenceAsHashMap::const_iterator aOverwriteIter = 806 GetMediaDescr().find( OUString("Overwrite") ); 807 808 // the file name must be specified if overwrite option is set 809 if ( aOverwriteIter != GetMediaDescr().end() ) 810 throw task::ErrorCodeIOException( 811 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_INVALIDPARAMETER", 812 uno::Reference< uno::XInterface >(), 813 sal_uInt32(ERRCODE_IO_INVALIDPARAMETER)); 814 815 // no target file name is specified 816 // we need to show the file dialog 817 818 // check if we have a filter which allows for filter options, so we need a corresponding checkbox in the dialog 819 bool bAllowOptions = false; 820 821 // in case of Export, filter options dialog is used if available 822 if( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) 823 bAllowOptions = CheckFilterOptionsDialogExistence(); 824 825 // get the filename by dialog ... 826 // create the file dialog 827 sal_Int16 aDialogMode = bAllowOptions 828 ? css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD_FILTEROPTIONS 829 : css::ui::dialogs::TemplateDescription::FILESAVE_AUTOEXTENSION_PASSWORD; 830 FileDialogFlags aDialogFlags = FileDialogFlags::NONE; 831 832 if( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) 833 { 834 if ( (nStoreMode & PDFEXPORT_REQUESTED) || (nStoreMode & EPUBEXPORT_REQUESTED) ) 835 aDialogMode = css::ui::dialogs::TemplateDescription:: 836 FILESAVE_AUTOEXTENSION; 837 else 838 aDialogMode = css::ui::dialogs::TemplateDescription:: 839 FILESAVE_AUTOEXTENSION_SELECTION; 840 aDialogFlags = FileDialogFlags::Export; 841 } 842 843 if( ( nStoreMode & EXPORT_REQUESTED ) && ( nStoreMode & SAVEACOPY_REQUESTED ) && ( nStoreMode & WIDEEXPORT_REQUESTED ) ) 844 { 845 aDialogFlags = FileDialogFlags::SaveACopy; 846 } 847 848 std::unique_ptr<sfx2::FileDialogHelper> pFileDlg; 849 850 const OUString aDocServiceName {GetDocServiceName()}; 851 DBG_ASSERT( !aDocServiceName.isEmpty(), "No document service for this module set!" ); 852 853 SfxFilterFlags nMust = getMustFlags( nStoreMode ); 854 SfxFilterFlags nDont = getDontFlags( nStoreMode ); 855 vcl::Window* pWin = SfxStoringHelper::GetModelWindow( m_xModel ); 856 weld::Window* pFrameWin = pWin ? pWin->GetFrameWeld() : nullptr; 857 if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) 858 { 859 if ( ( nStoreMode & PDFEXPORT_REQUESTED ) && !aPreselectedFilterPropsHM.empty() ) 860 { 861 // this is a PDF export 862 // the filter options has been shown already 863 const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ); 864 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aFilterUIName, "pdf", rStandardDir, rBlackList, pFrameWin )); 865 pFileDlg->SetCurrentFilter( aFilterUIName ); 866 } 867 else if ((nStoreMode & EPUBEXPORT_REQUESTED) && !aPreselectedFilterPropsHM.empty()) 868 { 869 // This is an EPUB export, the filter options has been shown already. 870 const OUString aFilterUIName = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ); 871 pFileDlg.reset(new sfx2::FileDialogHelper(aDialogMode, aDialogFlags, aFilterUIName, "epub", rStandardDir, rBlackList, pFrameWin)); 872 pFileDlg->SetCurrentFilter(aFilterUIName); 873 } 874 else 875 { 876 // This is the normal dialog 877 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, nMust, nDont, rStandardDir, rBlackList, pFrameWin )); 878 } 879 880 sfx2::FileDialogHelper::Context eCtxt = sfx2::FileDialogHelper::UNKNOWN_CONTEXT; 881 if ( aDocServiceName == "com.sun.star.drawing.DrawingDocument" ) 882 eCtxt = sfx2::FileDialogHelper::SD_EXPORT; 883 else if ( aDocServiceName == "com.sun.star.presentation.PresentationDocument" ) 884 eCtxt = sfx2::FileDialogHelper::SI_EXPORT; 885 else if ( aDocServiceName == "com.sun.star.text.TextDocument" ) 886 eCtxt = sfx2::FileDialogHelper::SW_EXPORT; 887 888 if ( eCtxt != sfx2::FileDialogHelper::UNKNOWN_CONTEXT ) 889 pFileDlg->SetContext( eCtxt ); 890 891 pFileDlg->CreateMatcher( aDocServiceName ); 892 893 uno::Reference< ui::dialogs::XFilePicker3 > xFilePicker = pFileDlg->GetFilePicker(); 894 uno::Reference< ui::dialogs::XFilePickerControlAccess > xControlAccess = 895 uno::Reference< ui::dialogs::XFilePickerControlAccess >( xFilePicker, uno::UNO_QUERY ); 896 897 if ( xControlAccess.is() ) 898 { 899 xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::PUSHBUTTON_OK, SfxResId(STR_EXPORTBUTTON) ); 900 xControlAccess->setLabel( ui::dialogs::CommonFilePickerElementIds::LISTBOX_FILTER_LABEL, SfxResId(STR_LABEL_FILEFORMAT) ); 901 } 902 } 903 else 904 { 905 // This is the normal dialog 906 pFileDlg.reset(new sfx2::FileDialogHelper( aDialogMode, aDialogFlags, aDocServiceName, nDialog, 907 nMust, nDont, rStandardDir, rBlackList, pFrameWin )); 908 pFileDlg->CreateMatcher( aDocServiceName ); 909 } 910 911 OUString aAdjustToType; 912 913 const OUString sFilterNameString(aFilterNameString); 914 915 if ( ( nStoreMode & EXPORT_REQUESTED ) && !( nStoreMode & WIDEEXPORT_REQUESTED ) ) 916 { 917 // it is export, set the preselected filter 918 pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ) ); 919 aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() ); 920 } 921 // it is no export, bSetStandardName == true means that user agreed to store document in the default (default default ;-)) format 922 else if ( bSetStandardName || GetStorable()->hasLocation() ) 923 { 924 uno::Sequence< beans::PropertyValue > aOldFilterProps; 925 const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 926 927 if ( !aOldFilterName.isEmpty() ) 928 m_pOwner->GetFilterConfiguration()->getByName( aOldFilterName ) >>= aOldFilterProps; 929 930 ::comphelper::SequenceAsHashMap aOldFiltPropsHM( aOldFilterProps ); 931 SfxFilterFlags nOldFiltFlags = static_cast<SfxFilterFlags>(aOldFiltPropsHM.getUnpackedValueOrDefault("Flags", sal_Int32(0) )); 932 933 if ( bSetStandardName || ( nOldFiltFlags & nMust ) != nMust || bool(nOldFiltFlags & nDont) ) 934 { 935 // the suggested type will be changed, the extension should be adjusted 936 aAdjustToType = aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "Type", OUString() ); 937 pFileDlg->SetCurrentFilter( aPreselectedFilterPropsHM.getUnpackedValueOrDefault( "UIName", OUString() ) ); 938 } 939 else 940 { 941 pFileDlg->SetCurrentFilter( aOldFiltPropsHM.getUnpackedValueOrDefault( 942 "UIName", 943 OUString() ) ); 944 } 945 } 946 947 const OUString aRecommendedDir {GetRecommendedDir( aSuggestedDir )}; 948 if ( !aRecommendedDir.isEmpty() ) 949 pFileDlg->SetDisplayFolder( aRecommendedDir ); 950 const OUString aRecommendedName {GetRecommendedName( aSuggestedName, aAdjustToType )}; 951 if ( !aRecommendedName.isEmpty() ) 952 pFileDlg->SetFileName( aRecommendedName ); 953 954 uno::Reference < view::XSelectionSupplier > xSel( GetModel()->getCurrentController(), uno::UNO_QUERY ); 955 if ( xSel.is() && xSel->getSelection().hasValue() ) 956 GetMediaDescr()[OUString("SelectionOnly")] <<= true; 957 958 // This is a temporary hardcoded solution must be removed when 959 // dialogs do not need parameters in SidSet representation any more 960 sal_uInt16 nSlotID = getSlotIDFromMode( nStoreMode ); 961 if ( !nSlotID ) 962 throw lang::IllegalArgumentException(); // TODO: 963 964 // generate SidSet from MediaDescriptor and provide it into FileDialog 965 // than merge changed SidSet back 966 std::unique_ptr<SfxItemSet> pDialogParams(new SfxAllItemSet( SfxGetpApp()->GetPool() )); 967 TransformParameters( nSlotID, 968 GetMediaDescr().getAsConstPropertyValueList(), 969 static_cast<SfxAllItemSet&>(*pDialogParams) ); 970 971 const SfxPoolItem* pItem = nullptr; 972 if ( bPreselectPassword && pDialogParams->GetItemState( SID_ENCRYPTIONDATA, true, &pItem ) != SfxItemState::SET ) 973 { 974 // the file dialog preselects the password checkbox if the provided mediadescriptor has encryption data entry 975 // after dialog execution the password interaction flag will be either removed or not 976 pDialogParams->Put( SfxBoolItem( SID_PASSWORDINTERACTION, true ) ); 977 } 978 979 // aFilterName is a pure output parameter, pDialogParams is an in/out parameter 980 OUString aFilterName; 981 if ( pFileDlg->Execute( pDialogParams, aFilterName ) != ERRCODE_NONE ) 982 { 983 throw task::ErrorCodeIOException( 984 "ModelData_Impl::OutputFileDialog: ERRCODE_IO_ABORT", 985 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); 986 } 987 988 // the following two arguments can not be converted in MediaDescriptor, 989 // so they should be removed from the ItemSet after retrieving 990 const SfxBoolItem* pRecommendReadOnly = SfxItemSet::GetItem<SfxBoolItem>(pDialogParams.get(), SID_RECOMMENDREADONLY, false); 991 m_bRecommendReadOnly = ( pRecommendReadOnly && pRecommendReadOnly->GetValue() ); 992 pDialogParams->ClearItem( SID_RECOMMENDREADONLY ); 993 994 uno::Sequence< beans::PropertyValue > aPropsFromDialog; 995 TransformItems( nSlotID, *pDialogParams, aPropsFromDialog ); 996 GetMediaDescr() << aPropsFromDialog; 997 998 // get the path from the dialog 999 INetURLObject aURL( pFileDlg->GetPath() ); 1000 // the path should be provided outside since it might be used for further calls to the dialog 1001 aSuggestedName = aURL.GetName( INetURLObject::DecodeMechanism::WithCharset ); 1002 aSuggestedDir = pFileDlg->GetDisplayDirectory(); 1003 1004 // old filter options should be cleared in case different filter is used 1005 1006 const OUString aFilterFromMediaDescr = GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 1007 const OUString aOldFilterName = GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 1008 1009 const OUString sFilterOptionsString(aFilterOptionsString); 1010 const OUString sFilterDataString(aFilterDataString); 1011 1012 if ( aFilterName == aFilterFromMediaDescr ) 1013 { 1014 // preserve current settings if any 1015 // if there no current settings and the name is the same 1016 // as old filter name use old filter settings 1017 1018 if ( aFilterFromMediaDescr == aOldFilterName ) 1019 { 1020 ::comphelper::SequenceAsHashMap::const_iterator aIter = 1021 GetDocProps().find( sFilterOptionsString ); 1022 if ( aIter != GetDocProps().end() 1023 && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() ) 1024 GetMediaDescr()[aIter->first] = aIter->second; 1025 1026 aIter = GetDocProps().find( sFilterDataString ); 1027 if ( aIter != GetDocProps().end() 1028 && GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end() ) 1029 GetMediaDescr()[aIter->first] = aIter->second; 1030 } 1031 } 1032 else 1033 { 1034 GetMediaDescr().erase( sFilterDataString ); 1035 GetMediaDescr().erase( sFilterOptionsString ); 1036 1037 if ( aFilterName == aOldFilterName ) 1038 { 1039 // merge filter option of the document filter 1040 1041 ::comphelper::SequenceAsHashMap::const_iterator aIter = 1042 GetDocProps().find( sFilterOptionsString ); 1043 if ( aIter != GetDocProps().end() ) 1044 GetMediaDescr()[aIter->first] = aIter->second; 1045 1046 aIter = GetDocProps().find( sFilterDataString ); 1047 if ( aIter != GetDocProps().end() ) 1048 GetMediaDescr()[aIter->first] = aIter->second; 1049 } 1050 } 1051 1052 uno::Reference< ui::dialogs::XFilePickerControlAccess > xExtFileDlg( pFileDlg->GetFilePicker(), uno::UNO_QUERY ); 1053 if ( xExtFileDlg.is() ) 1054 { 1055 if ( SfxStoringHelper::CheckFilterOptionsAppearance( m_pOwner->GetFilterConfiguration(), aFilterName ) ) 1056 bUseFilterOptions = true; 1057 1058 if ( ( !( nStoreMode & EXPORT_REQUESTED ) || ( nStoreMode & WIDEEXPORT_REQUESTED ) ) && bUseFilterOptions ) 1059 { 1060 try 1061 { 1062 // for exporters: always show dialog if format uses options 1063 // for save: show dialog if format uses options and no options given or if forced by user 1064 uno::Any aVal = 1065 xExtFileDlg->getValue( ui::dialogs::ExtendedFilePickerElementIds::CHECKBOX_FILTEROPTIONS, 0 ); 1066 1067 aVal >>= bUseFilterOptions; 1068 if ( !bUseFilterOptions ) 1069 bUseFilterOptions = 1070 ( GetMediaDescr().find( sFilterDataString ) == GetMediaDescr().end() 1071 && GetMediaDescr().find( sFilterOptionsString ) == GetMediaDescr().end() ); 1072 } 1073 catch( const lang::IllegalArgumentException& ) 1074 {} 1075 } 1076 } 1077 1078 // merge in results of the dialog execution 1079 GetMediaDescr()[OUString("URL")] <<= aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 1080 GetMediaDescr()[sFilterNameString] <<= aFilterName; 1081 1082 return bUseFilterOptions; 1083 } 1084 1085 1086 bool ModelData_Impl::ShowDocumentInfoDialog(const std::function< void () >& aFunc) 1087 { 1088 bool bDialogUsed = false; 1089 1090 try { 1091 uno::Reference< frame::XController > xController = GetModel()->getCurrentController(); 1092 if ( xController.is() ) 1093 { 1094 uno::Reference< frame::XDispatchProvider > xFrameDispatch( xController->getFrame(), uno::UNO_QUERY ); 1095 if ( xFrameDispatch.is() ) 1096 { 1097 util::URL aURL; 1098 aURL.Complete = ".uno:SetDocumentProperties"; 1099 1100 uno::Reference < util::XURLTransformer > xTransformer( util::URLTransformer::create( comphelper::getProcessComponentContext() ) ); 1101 if ( xTransformer->parseStrict( aURL ) ) 1102 { 1103 uno::Reference< frame::XDispatch > xDispatch = xFrameDispatch->queryDispatch( 1104 aURL, 1105 "_self", 1106 0 ); 1107 if ( xDispatch.is() ) 1108 { 1109 uno::Sequence< beans::PropertyValue > aProperties(1); 1110 uno::Reference< lang::XUnoTunnel > aAsyncFunc(new AsyncFunc(aFunc)); 1111 aProperties[0].Name = "AsyncFunc"; 1112 aProperties[0].Value <<= aAsyncFunc; 1113 xDispatch->dispatch( aURL, aProperties ); 1114 bDialogUsed = true; 1115 } 1116 } 1117 } 1118 } 1119 } 1120 catch ( const uno::Exception& ) 1121 { 1122 } 1123 1124 return bDialogUsed; 1125 } 1126 1127 1128 OUString ModelData_Impl::GetRecommendedExtension( const OUString& aTypeName ) 1129 { 1130 if ( aTypeName.isEmpty() ) 1131 return OUString(); 1132 1133 uno::Reference< container::XNameAccess > xTypeDetection( 1134 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), 1135 uno::UNO_QUERY ); 1136 if ( xTypeDetection.is() ) 1137 { 1138 uno::Sequence< beans::PropertyValue > aTypeNameProps; 1139 if ( ( xTypeDetection->getByName( aTypeName ) >>= aTypeNameProps ) && aTypeNameProps.hasElements() ) 1140 { 1141 ::comphelper::SequenceAsHashMap aTypeNamePropsHM( aTypeNameProps ); 1142 uno::Sequence< OUString > aExtensions = aTypeNamePropsHM.getUnpackedValueOrDefault( 1143 "Extensions", 1144 ::uno::Sequence< OUString >() ); 1145 if ( aExtensions.hasElements() ) 1146 return aExtensions[0]; 1147 } 1148 } 1149 1150 return OUString(); 1151 } 1152 1153 1154 OUString ModelData_Impl::GetRecommendedDir( const OUString& aSuggestedDir ) 1155 { 1156 if ( ( !aSuggestedDir.isEmpty() || GetStorable()->hasLocation() ) 1157 && !GetMediaDescr().getUnpackedValueOrDefault("RepairPackage", false ) ) 1158 { 1159 INetURLObject aLocation; 1160 if ( !aSuggestedDir.isEmpty() ) 1161 aLocation = INetURLObject( aSuggestedDir ); 1162 else 1163 { 1164 const OUString aOldURL = GetStorable()->getLocation(); 1165 if ( !aOldURL.isEmpty() ) 1166 { 1167 INetURLObject aTmp( aOldURL ); 1168 if ( aTmp.removeSegment() ) 1169 aLocation = aTmp; 1170 } 1171 1172 if ( aLocation.HasError() ) 1173 aLocation = INetURLObject( SvtPathOptions().GetWorkPath() ); 1174 } 1175 1176 OUString sLocationURL( aLocation.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); 1177 bool bIsInTempPath( false ); 1178 OUString sSysTempPath; 1179 if( osl::FileBase::getTempDirURL( sSysTempPath ) == osl::FileBase::E_None ) 1180 bIsInTempPath = !sSysTempPath.isEmpty() && sLocationURL.startsWith( sSysTempPath ); 1181 #ifdef _WIN32 1182 if( !bIsInTempPath ) 1183 { 1184 wchar_t sPath[MAX_PATH+1]; 1185 HRESULT hRes = SHGetFolderPathW( nullptr, CSIDL_INTERNET_CACHE, nullptr, SHGFP_TYPE_CURRENT, sPath ); 1186 if( SUCCEEDED(hRes) ) 1187 { 1188 OUString sTempINetFiles; 1189 if( osl::FileBase::getFileURLFromSystemPath(o3tl::toU(sPath), sTempINetFiles) == osl::FileBase::E_None ) 1190 bIsInTempPath = !sTempINetFiles.isEmpty() && sLocationURL.startsWith( sTempINetFiles ); 1191 } 1192 } 1193 #endif 1194 // Suggest somewhere other than the system's temp directory 1195 if( bIsInTempPath ) 1196 aLocation = INetURLObject( SvtPathOptions().GetWorkPath() ); 1197 1198 aLocation.setFinalSlash(); 1199 if ( !aLocation.HasError() ) 1200 return aLocation.GetMainURL( INetURLObject::DecodeMechanism::NONE ); 1201 1202 return OUString(); 1203 } 1204 1205 return INetURLObject( SvtPathOptions().GetWorkPath() ).GetMainURL( INetURLObject::DecodeMechanism::NONE ); 1206 } 1207 1208 1209 OUString ModelData_Impl::GetRecommendedName( const OUString& aSuggestedName, const OUString& aTypeName ) 1210 { 1211 // the last used name might be provided by aSuggestedName from the old selection, or from the MediaDescriptor 1212 if ( !aSuggestedName.isEmpty() ) 1213 return aSuggestedName; 1214 1215 OUString aRecommendedName {INetURLObject( GetStorable()->getLocation() ).GetName( INetURLObject::DecodeMechanism::WithCharset )}; 1216 if ( aRecommendedName.isEmpty() ) 1217 { 1218 try { 1219 uno::Reference< frame::XTitle > xTitle( GetModel(), uno::UNO_QUERY_THROW ); 1220 aRecommendedName = xTitle->getTitle(); 1221 } catch( const uno::Exception& ) {} 1222 } 1223 1224 if ( !aRecommendedName.isEmpty() && !aTypeName.isEmpty() ) 1225 { 1226 // adjust the extension to the type 1227 uno::Reference< container::XNameAccess > xTypeDetection( 1228 comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.TypeDetection"), 1229 uno::UNO_QUERY ); 1230 if ( xTypeDetection.is() ) 1231 { 1232 INetURLObject aObj( "c:/" + aRecommendedName, INetProtocol::File, 1233 INetURLObject::EncodeMechanism::All, RTL_TEXTENCODING_UTF8, FSysStyle::Dos ); 1234 1235 const OUString aExtension = GetRecommendedExtension( aTypeName ); 1236 if ( !aExtension.isEmpty() ) 1237 aObj.SetExtension( aExtension ); 1238 1239 aRecommendedName = aObj.GetName( INetURLObject::DecodeMechanism::WithCharset ); 1240 } 1241 } 1242 1243 return aRecommendedName; 1244 } 1245 1246 1247 // class SfxStoringHelper 1248 1249 1250 SfxStoringHelper::SfxStoringHelper() 1251 { 1252 } 1253 1254 1255 uno::Reference< container::XNameAccess > const & SfxStoringHelper::GetFilterConfiguration() 1256 { 1257 if ( !m_xFilterCFG.is() ) 1258 { 1259 m_xFilterCFG.set( comphelper::getProcessServiceFactory()->createInstance("com.sun.star.document.FilterFactory"), 1260 uno::UNO_QUERY_THROW ); 1261 } 1262 1263 return m_xFilterCFG; 1264 } 1265 1266 1267 uno::Reference< container::XContainerQuery > const & SfxStoringHelper::GetFilterQuery() 1268 { 1269 if ( !m_xFilterQuery.is() ) 1270 { 1271 m_xFilterQuery.set( GetFilterConfiguration(), uno::UNO_QUERY_THROW ); 1272 } 1273 1274 return m_xFilterQuery; 1275 } 1276 1277 1278 uno::Reference< css::frame::XModuleManager2 > const & SfxStoringHelper::GetModuleManager() 1279 { 1280 if ( !m_xModuleManager.is() ) 1281 { 1282 m_xModuleManager = frame::ModuleManager::create( 1283 comphelper::getProcessComponentContext() ); 1284 } 1285 1286 return m_xModuleManager; 1287 } 1288 1289 1290 bool SfxStoringHelper::GUIStoreModel( const uno::Reference< frame::XModel >& xModel, 1291 const OUString& aSlotName, 1292 uno::Sequence< beans::PropertyValue >& aArgsSequence, 1293 bool bPreselectPassword, 1294 SignatureState nDocumentSignatureState ) 1295 { 1296 ModelData_Impl aModelData( *this, xModel, aArgsSequence ); 1297 1298 bool bDialogUsed = false; 1299 1300 INetURLObject aURL; 1301 1302 bool bSetStandardName = false; // can be set only for SaveAs 1303 1304 // parse the slot name 1305 bool bRemote = false; 1306 sal_Int16 nStoreMode = getStoreModeFromSlotName( aSlotName ); 1307 1308 if ( nStoreMode == SAVEASREMOTE_REQUESTED ) 1309 { 1310 nStoreMode = SAVEAS_REQUESTED; 1311 bRemote = true; 1312 } 1313 1314 sal_Int8 nStatusSave = STATUS_NO_ACTION; 1315 1316 ::comphelper::SequenceAsHashMap::const_iterator aSaveACopyIter = 1317 aModelData.GetMediaDescr().find( OUString("SaveACopy") ); 1318 if ( aSaveACopyIter != aModelData.GetMediaDescr().end() ) 1319 { 1320 bool bSaveACopy = false; 1321 aSaveACopyIter->second >>= bSaveACopy; 1322 if ( bSaveACopy ) 1323 nStoreMode = EXPORT_REQUESTED | SAVEACOPY_REQUESTED | WIDEEXPORT_REQUESTED; 1324 } 1325 // handle the special cases 1326 if ( nStoreMode & SAVEAS_REQUESTED ) 1327 { 1328 ::comphelper::SequenceAsHashMap::const_iterator aSaveToIter = 1329 aModelData.GetMediaDescr().find( OUString("SaveTo") ); 1330 if ( aSaveToIter != aModelData.GetMediaDescr().end() ) 1331 { 1332 bool bWideExport = false; 1333 aSaveToIter->second >>= bWideExport; 1334 if ( bWideExport ) 1335 nStoreMode = EXPORT_REQUESTED | WIDEEXPORT_REQUESTED; 1336 } 1337 1338 // if saving is not acceptable the warning must be shown even in case of SaveAs operation 1339 if ( ( nStoreMode & SAVEAS_REQUESTED ) && aModelData.CheckSaveAcceptable( STATUS_SAVEAS ) == STATUS_NO_ACTION ) 1340 throw task::ErrorCodeIOException( 1341 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT", 1342 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); 1343 } 1344 else if ( nStoreMode & SAVE_REQUESTED ) 1345 { 1346 // if saving is not acceptable by the configuration the warning must be shown 1347 nStatusSave = aModelData.CheckSaveAcceptable( STATUS_SAVE ); 1348 1349 if ( nStatusSave == STATUS_NO_ACTION ) 1350 throw task::ErrorCodeIOException( 1351 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT", 1352 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); 1353 else if ( nStatusSave == STATUS_SAVE ) 1354 { 1355 // check whether it is possible to use save operation 1356 nStatusSave = aModelData.CheckStateForSave(); 1357 } 1358 1359 if ( nStatusSave == STATUS_NO_ACTION ) 1360 { 1361 throw task::ErrorCodeIOException( 1362 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT", 1363 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); 1364 } 1365 else if ( nStatusSave != STATUS_SAVE ) 1366 { 1367 // this should be a usual SaveAs operation 1368 nStoreMode = SAVEAS_REQUESTED; 1369 if ( nStatusSave == STATUS_SAVEAS_STANDARDNAME ) 1370 bSetStandardName = true; 1371 } 1372 } 1373 1374 if (!comphelper::LibreOfficeKit::isActive() && !( nStoreMode & EXPORT_REQUESTED ) ) 1375 { 1376 // if it is no export, warn user that the signature will be removed 1377 if ( SignatureState::OK == nDocumentSignatureState 1378 || SignatureState::INVALID == nDocumentSignatureState 1379 || SignatureState::NOTVALIDATED == nDocumentSignatureState 1380 || SignatureState::PARTIAL_OK == nDocumentSignatureState) 1381 { 1382 vcl::Window* pWin = SfxStoringHelper::GetModelWindow( xModel ); 1383 std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(pWin ? pWin->GetFrameWeld() : nullptr, 1384 VclMessageType::Question, VclButtonsType::YesNo, SfxResId(RID_SVXSTR_XMLSEC_QUERY_LOSINGSIGNATURE))); 1385 if (xMessageBox->run() != RET_YES) 1386 { 1387 // the user has decided not to store the document 1388 throw task::ErrorCodeIOException( 1389 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_ABORT (Preserve Signature)", 1390 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_ABORT)); 1391 } 1392 } 1393 } 1394 1395 if ( nStoreMode & SAVE_REQUESTED && nStatusSave == STATUS_SAVE ) 1396 { 1397 // Document properties can contain streams that should be freed before storing 1398 aModelData.FreeDocumentProps(); 1399 1400 if ( aModelData.GetStorable2().is() ) 1401 { 1402 try 1403 { 1404 aModelData.GetStorable2()->storeSelf( aModelData.GetMediaDescr().getAsConstPropertyValueList() ); 1405 } 1406 catch (const lang::IllegalArgumentException& e) 1407 { 1408 SAL_WARN("sfx.doc", "Ignoring parameters! " 1409 "ModelData considers this illegal: " << e); 1410 aModelData.GetStorable()->store(); 1411 } 1412 } 1413 else 1414 { 1415 OSL_FAIL( "XStorable2 is not supported by the model!" ); 1416 aModelData.GetStorable()->store(); 1417 } 1418 1419 return false; 1420 } 1421 1422 // preselect a filter for the storing process 1423 uno::Sequence< beans::PropertyValue > aFilterProps = aModelData.GetPreselectedFilter_Impl( nStoreMode ); 1424 1425 DBG_ASSERT( aFilterProps.hasElements(), "No filter for storing!\n" ); 1426 if ( !aFilterProps.hasElements() ) 1427 throw task::ErrorCodeIOException( 1428 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER", 1429 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER)); 1430 1431 ::comphelper::SequenceAsHashMap aFilterPropsHM( aFilterProps ); 1432 OUString aFilterName = aFilterPropsHM.getUnpackedValueOrDefault( "Name", OUString() ); 1433 1434 const OUString sFilterNameString(aFilterNameString); 1435 1436 const OUString aFilterFromMediaDescr = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 1437 const OUString aOldFilterName = aModelData.GetDocProps().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 1438 1439 bool bUseFilterOptions = false; 1440 ::comphelper::SequenceAsHashMap::const_iterator aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") ); 1441 1442 const OUString sFilterOptionsString(aFilterOptionsString); 1443 const OUString sFilterDataString(aFilterDataString); 1444 const OUString sFilterFlagsString("FilterFlags"); 1445 1446 bool bPDFOptions = (nStoreMode & PDFEXPORT_REQUESTED) && !(nStoreMode & PDFDIRECTEXPORT_REQUESTED); 1447 bool bEPUBOptions = (nStoreMode & EPUBEXPORT_REQUESTED) && !(nStoreMode & EPUBDIRECTEXPORT_REQUESTED); 1448 if ( ( nStoreMode & EXPORT_REQUESTED ) && (bPDFOptions || bEPUBOptions) ) 1449 { 1450 // this is PDF or EPUB export, the filter options dialog should be shown before the export 1451 aModelData.GetMediaDescr()[sFilterNameString] <<= aFilterName; 1452 if ( aModelData.GetMediaDescr().find( sFilterFlagsString ) == aModelData.GetMediaDescr().end() 1453 && aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end() 1454 && aModelData.GetMediaDescr().find( sFilterDataString ) == aModelData.GetMediaDescr().end() ) 1455 { 1456 // execute filter options dialog since no options are set in the media descriptor 1457 if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) 1458 bDialogUsed = true; 1459 } 1460 } 1461 1462 if ( aFileNameIter == aModelData.GetMediaDescr().end() ) 1463 { 1464 sal_Int16 nDialog = SFX2_IMPL_DIALOG_CONFIG; 1465 1466 if( bRemote ) 1467 { 1468 nDialog = SFX2_IMPL_DIALOG_REMOTE; 1469 } 1470 else 1471 { 1472 ::comphelper::SequenceAsHashMap::const_iterator aDlgIter = 1473 aModelData.GetMediaDescr().find( OUString("UseSystemDialog") ); 1474 if ( aDlgIter != aModelData.GetMediaDescr().end() ) 1475 { 1476 bool bUseSystemDialog = true; 1477 if ( aDlgIter->second >>= bUseSystemDialog ) 1478 { 1479 if ( bUseSystemDialog ) 1480 nDialog = SFX2_IMPL_DIALOG_SYSTEM; 1481 else 1482 nDialog = SFX2_IMPL_DIALOG_OOO; 1483 } 1484 } 1485 } 1486 1487 // The Dispatch supports parameter FolderName that overwrites SuggestedSaveAsDir 1488 OUString aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault("FolderName", OUString() ); 1489 if ( aSuggestedDir.isEmpty() ) 1490 { 1491 aSuggestedDir = aModelData.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() ); 1492 if ( aSuggestedDir.isEmpty() ) 1493 aSuggestedDir = aModelData.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsDir", OUString() ); 1494 } 1495 1496 OUString aSuggestedName = aModelData.GetMediaDescr().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() ); 1497 if ( aSuggestedName.isEmpty() ) 1498 aSuggestedName = aModelData.GetDocProps().getUnpackedValueOrDefault("SuggestedSaveAsName", OUString() ); 1499 1500 OUString sStandardDir; 1501 ::comphelper::SequenceAsHashMap::const_iterator aStdDirIter = 1502 aModelData.GetMediaDescr().find( OUString("StandardDir") ); 1503 if ( aStdDirIter != aModelData.GetMediaDescr().end() ) 1504 aStdDirIter->second >>= sStandardDir; 1505 1506 css::uno::Sequence< OUString > aBlackList; 1507 1508 ::comphelper::SequenceAsHashMap::const_iterator aBlackListIter = 1509 aModelData.GetMediaDescr().find( OUString("BlackList") ); 1510 if ( aBlackListIter != aModelData.GetMediaDescr().end() ) 1511 aBlackListIter->second >>= aBlackList; 1512 1513 for (;;) 1514 { 1515 // in case the dialog is opened a second time the folder should be the same as previously navigated to by the user, not what was handed over by initial parameters 1516 bUseFilterOptions = aModelData.OutputFileDialog( nStoreMode, aFilterProps, bSetStandardName, aSuggestedName, bPreselectPassword, aSuggestedDir, nDialog, sStandardDir, aBlackList ); 1517 if ( nStoreMode == SAVEAS_REQUESTED ) 1518 { 1519 // in case of saving check filter for possible alien warning 1520 const OUString aSelFilterName = aModelData.GetMediaDescr().getUnpackedValueOrDefault( sFilterNameString, OUString() ); 1521 sal_Int8 nStatusFilterSave = aModelData.CheckFilter( aSelFilterName ); 1522 if ( nStatusFilterSave == STATUS_SAVEAS_STANDARDNAME ) 1523 { 1524 // switch to best filter 1525 bSetStandardName = true; 1526 } 1527 else if ( nStatusFilterSave == STATUS_SAVE ) 1528 { 1529 // user confirmed alien filter or "good" filter is used 1530 break; 1531 } 1532 } 1533 else 1534 break; 1535 } 1536 1537 bDialogUsed = true; 1538 aFileNameIter = aModelData.GetMediaDescr().find( OUString("URL") ); 1539 } 1540 else 1541 { 1542 // the target file name is provided so check if new filter options 1543 // are provided or old options can be used 1544 if ( aFilterFromMediaDescr == aOldFilterName ) 1545 { 1546 ::comphelper::SequenceAsHashMap::const_iterator aIter = 1547 aModelData.GetDocProps().find( sFilterOptionsString ); 1548 if ( aIter != aModelData.GetDocProps().end() 1549 && aModelData.GetMediaDescr().find( sFilterOptionsString ) == aModelData.GetMediaDescr().end() ) 1550 aModelData.GetMediaDescr()[aIter->first] = aIter->second; 1551 1552 aIter = aModelData.GetDocProps().find( sFilterDataString ); 1553 if ( aIter != aModelData.GetDocProps().end() 1554 && aModelData.GetMediaDescr().find( sFilterDataString ) == aModelData.GetMediaDescr().end() ) 1555 aModelData.GetMediaDescr()[aIter->first] = aIter->second; 1556 } 1557 } 1558 1559 if ( aFileNameIter != aModelData.GetMediaDescr().end() ) 1560 { 1561 OUString aFileName; 1562 aFileNameIter->second >>= aFileName; 1563 aURL.SetURL( aFileName ); 1564 DBG_ASSERT( aURL.GetProtocol() != INetProtocol::NotValid, "Illegal URL!" ); 1565 1566 ::comphelper::SequenceAsHashMap::const_iterator aIter = 1567 aModelData.GetMediaDescr().find( sFilterNameString ); 1568 1569 if ( aIter != aModelData.GetMediaDescr().end() ) 1570 aIter->second >>= aFilterName; 1571 else 1572 aModelData.GetMediaDescr()[sFilterNameString] <<= aFilterName; 1573 1574 DBG_ASSERT( !aFilterName.isEmpty(), "Illegal filter!" ); 1575 } 1576 else 1577 { 1578 SAL_WARN( "sfx.doc", "This code must be unreachable!" ); 1579 throw task::ErrorCodeIOException( 1580 "SfxStoringHelper::GUIStoreModel: ERRCODE_IO_INVALIDPARAMETER", 1581 uno::Reference< uno::XInterface >(), sal_uInt32(ERRCODE_IO_INVALIDPARAMETER)); 1582 } 1583 1584 ::comphelper::SequenceAsHashMap::const_iterator aIter = 1585 aModelData.GetMediaDescr().find( OUString("FilterFlags") ); 1586 bool bFilterFlagsSet = ( aIter != aModelData.GetMediaDescr().end() ); 1587 1588 if( !( nStoreMode & PDFEXPORT_REQUESTED ) && !( nStoreMode & EPUBEXPORT_REQUESTED ) && !bFilterFlagsSet 1589 && ( ( nStoreMode & EXPORT_REQUESTED ) || bUseFilterOptions ) ) 1590 { 1591 // execute filter options dialog 1592 if ( aModelData.ExecuteFilterDialog_Impl( aFilterName ) ) 1593 bDialogUsed = true; 1594 } 1595 1596 // so the arguments will not change any more and can be stored to the main location 1597 aArgsSequence = aModelData.GetMediaDescr().getAsConstPropertyValueList(); 1598 1599 // store the document and handle it's docinfo 1600 SvtSaveOptions aOptions; 1601 1602 DocumentSettingsGuard aSettingsGuard( aModelData.GetModel(), aModelData.IsRecommendReadOnly(), nStoreMode & EXPORT_REQUESTED ); 1603 1604 OSL_ENSURE( aModelData.GetMediaDescr().find( OUString( "Password" ) ) == aModelData.GetMediaDescr().end(), "The Password property of MediaDescriptor should not be used here!" ); 1605 if ( aOptions.IsDocInfoSave() 1606 && ( !aModelData.GetStorable()->hasLocation() 1607 || INetURLObject( aModelData.GetStorable()->getLocation() ) != aURL ) ) 1608 { 1609 // this is definitely not a Save operation 1610 // so the document info can be updated 1611 1612 // on export document info must be preserved 1613 uno::Reference<document::XDocumentPropertiesSupplier> xDPS( 1614 aModelData.GetModel(), uno::UNO_QUERY_THROW); 1615 uno::Reference<util::XCloneable> xCloneable( 1616 xDPS->getDocumentProperties(), uno::UNO_QUERY_THROW); 1617 uno::Reference<document::XDocumentProperties> xOldDocProps( 1618 xCloneable->createClone(), uno::UNO_QUERY_THROW); 1619 1620 std::function< void () > aFunc = [xModel, xOldDocProps, nStoreMode, aURL, aArgsSequence]() { 1621 SfxStoringHelper aStoringHelper; 1622 ModelData_Impl aModel(aStoringHelper, xModel, aArgsSequence ); 1623 1624 try 1625 { 1626 if ( nStoreMode & EXPORT_REQUESTED ) 1627 aModel.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); 1628 else 1629 aModel.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); 1630 } 1631 catch( const uno::Exception& ) 1632 { 1633 } 1634 1635 if ( nStoreMode & EXPORT_REQUESTED ) 1636 { 1637 SfxStoringHelper::SetDocInfoState(aModel.GetModel(), xOldDocProps); 1638 } 1639 }; 1640 1641 // use dispatch API to show document info dialog 1642 if ( aModelData.ShowDocumentInfoDialog(aFunc) ) 1643 bDialogUsed = true; 1644 else 1645 { 1646 OSL_FAIL( "Can't execute document info dialog!" ); 1647 } 1648 } 1649 else 1650 { 1651 // Document properties can contain streams that should be freed before storing 1652 aModelData.FreeDocumentProps(); 1653 1654 // this is actually a save operation with different parameters 1655 // so storeTo or storeAs without DocInfo operations are used 1656 if ( nStoreMode & EXPORT_REQUESTED ) 1657 aModelData.GetStorable()->storeToURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); 1658 else 1659 aModelData.GetStorable()->storeAsURL( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), aArgsSequence ); 1660 } 1661 1662 // Launch PDF viewer 1663 if ( nStoreMode & PDFEXPORT_REQUESTED ) 1664 { 1665 FilterConfigItem aItem( "Office.Common/Filter/PDF/Export/" ); 1666 bool aViewPDF = aItem.ReadBool( "ViewPDFAfterExport", false ); 1667 1668 if ( aViewPDF ) 1669 { 1670 uno::Reference<XSystemShellExecute> xSystemShellExecute(SystemShellExecute::create( ::comphelper::getProcessComponentContext() ) ); 1671 xSystemShellExecute->execute( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), "", SystemShellExecuteFlags::URIS_ONLY ); 1672 } 1673 } 1674 1675 return bDialogUsed; 1676 } 1677 1678 1679 // static 1680 bool SfxStoringHelper::CheckFilterOptionsAppearance( 1681 const uno::Reference< container::XNameAccess >& xFilterCFG, 1682 const OUString& aFilterName ) 1683 { 1684 bool bUseFilterOptions = false; 1685 1686 DBG_ASSERT( xFilterCFG.is(), "No filter configuration!\n" ); 1687 if( xFilterCFG.is() ) 1688 { 1689 try { 1690 uno::Sequence < beans::PropertyValue > aProps; 1691 uno::Any aAny = xFilterCFG->getByName( aFilterName ); 1692 if ( aAny >>= aProps ) 1693 { 1694 ::comphelper::SequenceAsHashMap aPropsHM( aProps ); 1695 if( !aPropsHM.getUnpackedValueOrDefault( "UIComponent", OUString() ).isEmpty() ) 1696 bUseFilterOptions = true; 1697 } 1698 } 1699 catch( const uno::Exception& ) 1700 { 1701 } 1702 } 1703 1704 return bUseFilterOptions; 1705 } 1706 1707 1708 // static 1709 void SfxStoringHelper::SetDocInfoState( 1710 const uno::Reference< frame::XModel >& xModel, 1711 const uno::Reference< document::XDocumentProperties>& i_xOldDocProps ) 1712 { 1713 uno::Reference<document::XDocumentPropertiesSupplier> const 1714 xModelDocPropsSupplier(xModel, uno::UNO_QUERY_THROW); 1715 uno::Reference<document::XDocumentProperties> const xDocPropsToFill = 1716 xModelDocPropsSupplier->getDocumentProperties(); 1717 uno::Reference< beans::XPropertySet > const xPropSet( 1718 i_xOldDocProps->getUserDefinedProperties(), uno::UNO_QUERY_THROW); 1719 1720 uno::Reference< util::XModifiable > xModifiable( xModel, uno::UNO_QUERY ); 1721 if ( !xModifiable.is() ) 1722 throw uno::RuntimeException(); 1723 1724 bool bIsModified = xModifiable->isModified(); 1725 1726 try 1727 { 1728 uno::Reference< beans::XPropertySet > const xSet( 1729 xDocPropsToFill->getUserDefinedProperties(), uno::UNO_QUERY); 1730 uno::Reference< beans::XPropertyContainer > xContainer( xSet, uno::UNO_QUERY ); 1731 uno::Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo(); 1732 uno::Sequence< beans::Property > lProps = xSetInfo->getProperties(); 1733 const beans::Property* pProps = lProps.getConstArray(); 1734 const sal_Int32 nPropLen = lProps.getLength(); 1735 for (sal_Int32 i=0; i<nPropLen; ++i) 1736 { 1737 uno::Any aValue = xPropSet->getPropertyValue( pProps[i].Name ); 1738 if ( pProps[i].Attributes & css::beans::PropertyAttribute::REMOVABLE ) 1739 { 1740 try 1741 { 1742 // QUESTION: DefaultValue?! 1743 xContainer->addProperty( pProps[i].Name, pProps[i].Attributes, aValue ); 1744 } 1745 catch (beans::PropertyExistException const&) {} 1746 try 1747 { 1748 // it is possible that the propertysets from XML and binary files differ; we shouldn't break then 1749 xSet->setPropertyValue( pProps[i].Name, aValue ); 1750 } 1751 catch ( const uno::Exception& ) {} 1752 } 1753 } 1754 1755 // sigh... have to set these manually I'm afraid... wonder why 1756 // SfxObjectShell doesn't handle this internally, should be easier 1757 xDocPropsToFill->setAuthor(i_xOldDocProps->getAuthor()); 1758 xDocPropsToFill->setGenerator(i_xOldDocProps->getGenerator()); 1759 xDocPropsToFill->setCreationDate(i_xOldDocProps->getCreationDate()); 1760 xDocPropsToFill->setTitle(i_xOldDocProps->getTitle()); 1761 xDocPropsToFill->setSubject(i_xOldDocProps->getSubject()); 1762 xDocPropsToFill->setDescription(i_xOldDocProps->getDescription()); 1763 xDocPropsToFill->setKeywords(i_xOldDocProps->getKeywords()); 1764 xDocPropsToFill->setModifiedBy(i_xOldDocProps->getModifiedBy()); 1765 xDocPropsToFill->setModificationDate(i_xOldDocProps->getModificationDate()); 1766 xDocPropsToFill->setPrintedBy(i_xOldDocProps->getPrintedBy()); 1767 xDocPropsToFill->setPrintDate(i_xOldDocProps->getPrintDate()); 1768 xDocPropsToFill->setAutoloadURL(i_xOldDocProps->getAutoloadURL()); 1769 xDocPropsToFill->setAutoloadSecs(i_xOldDocProps->getAutoloadSecs()); 1770 xDocPropsToFill->setDefaultTarget(i_xOldDocProps->getDefaultTarget()); 1771 xDocPropsToFill->setEditingCycles(i_xOldDocProps->getEditingCycles()); 1772 xDocPropsToFill->setEditingDuration(i_xOldDocProps->getEditingDuration()); 1773 // other attributes e.g. DocumentStatistics are not editable from dialog 1774 } 1775 catch (const uno::Exception& e) 1776 { 1777 SAL_INFO("sfx.doc", "SetDocInfoState: caught " << e); 1778 } 1779 1780 // set the modified flag back if required 1781 if ( bIsModified != bool(xModifiable->isModified()) ) 1782 xModifiable->setModified( bIsModified ); 1783 } 1784 1785 1786 // static 1787 bool SfxStoringHelper::WarnUnacceptableFormat( const uno::Reference< frame::XModel >& xModel, 1788 const OUString& aOldUIName, 1789 const OUString& aDefExtension, 1790 bool bDefIsAlien ) 1791 { 1792 if ( !SvtSaveOptions().IsWarnAlienFormat() ) 1793 return true; 1794 1795 vcl::Window* pWin = SfxStoringHelper::GetModelWindow( xModel ); 1796 SfxAlienWarningDialog aDlg(pWin ? pWin->GetFrameWeld() : nullptr, aOldUIName, aDefExtension, bDefIsAlien); 1797 1798 return aDlg.run() == RET_OK; 1799 } 1800 1801 uno::Reference<awt::XWindow> SfxStoringHelper::GetModelXWindow(const uno::Reference<frame::XModel>& xModel) 1802 { 1803 try { 1804 if ( xModel.is() ) 1805 { 1806 uno::Reference< frame::XController > xController = xModel->getCurrentController(); 1807 if ( xController.is() ) 1808 { 1809 uno::Reference< frame::XFrame > xFrame = xController->getFrame(); 1810 if ( xFrame.is() ) 1811 { 1812 return xFrame->getContainerWindow(); 1813 } 1814 } 1815 } 1816 } 1817 catch ( const uno::Exception& ) 1818 { 1819 } 1820 1821 return uno::Reference<awt::XWindow>(); 1822 } 1823 1824 vcl::Window* SfxStoringHelper::GetModelWindow( const uno::Reference< frame::XModel >& xModel ) 1825 { 1826 VclPtr<vcl::Window> pWin; 1827 1828 try { 1829 uno::Reference<awt::XWindow> xWindow = GetModelXWindow(xModel); 1830 if ( xWindow.is() ) 1831 { 1832 VCLXWindow* pVCLWindow = VCLXWindow::getImplementation( xWindow ); 1833 if ( pVCLWindow ) 1834 pWin = pVCLWindow->GetWindow(); 1835 } 1836 } 1837 catch ( const uno::Exception& ) 1838 { 1839 } 1840 1841 return pWin; 1842 } 1843 1844 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 1845
