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 <svx/svxdlg.hxx> 21 #include <sfx2/filedlghelper.hxx> 22 #include <sfx2/app.hxx> 23 #include <svl/aeitem.hxx> 24 #include <svtools/svtabbx.hxx> 25 #include <svtools/treelistentry.hxx> 26 #include <tools/urlobj.hxx> 27 #include <vcl/svapp.hxx> 28 #include <unotools/defaultoptions.hxx> 29 #include <unotools/localfilehelper.hxx> 30 #include <unotools/pathoptions.hxx> 31 #include <unotools/moduleoptions.hxx> 32 #include <unotools/viewoptions.hxx> 33 34 #include <optpath.hxx> 35 #include <dialmgr.hxx> 36 #include <strings.hrc> 37 #include <comphelper/configuration.hxx> 38 #include <comphelper/processfactory.hxx> 39 #include <comphelper/string.hxx> 40 #include <com/sun/star/uno/Exception.hpp> 41 #include <com/sun/star/beans/XPropertySet.hpp> 42 #include <com/sun/star/beans/PropertyAttribute.hpp> 43 #include <com/sun/star/lang/XMultiServiceFactory.hpp> 44 #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp> 45 #include <com/sun/star/ui/dialogs/XAsynchronousExecutableDialog.hpp> 46 #include <com/sun/star/ui/dialogs/FolderPicker.hpp> 47 #include <com/sun/star/ui/dialogs/FilePicker.hpp> 48 #include <com/sun/star/ui/dialogs/TemplateDescription.hpp> 49 #include <com/sun/star/util/thePathSettings.hpp> 50 #include <officecfg/Office/Common.hxx> 51 #include "optHeaderTabListbox.hxx" 52 #include <vcl/help.hxx> 53 #include <tools/diagnose_ex.h> 54 #include <sal/log.hxx> 55 56 using namespace css; 57 using namespace css::beans; 58 using namespace css::lang; 59 using namespace css::ui::dialogs; 60 using namespace css::uno; 61 using namespace svx; 62 63 // define ---------------------------------------------------------------- 64 65 #define TAB_WIDTH_MIN 10 66 #define ITEMID_TYPE 1 67 #define ITEMID_PATH 2 68 69 #define POSTFIX_INTERNAL "_internal" 70 #define POSTFIX_USER "_user" 71 #define POSTFIX_WRITABLE "_writable" 72 #define VAR_ONE "%1" 73 #define IODLG_CONFIGNAME "FilePicker_Save" 74 75 // struct OptPath_Impl --------------------------------------------------- 76 77 struct OptPath_Impl 78 { 79 SvtDefaultOptions m_aDefOpt; 80 Image m_aLockImage; 81 OUString m_sMultiPathDlg; 82 Reference< css::util::XPathSettings > m_xPathSettings; 83 84 OptPath_Impl(const Image& rLockImage, const OUString& rMultiPathDlg) 85 : m_aLockImage(rLockImage) 86 , m_sMultiPathDlg(rMultiPathDlg) 87 { 88 } 89 }; 90 91 // struct PathUserData_Impl ---------------------------------------------- 92 93 struct PathUserData_Impl 94 { 95 sal_uInt16 nRealId; 96 SfxItemState eState; 97 OUString sUserPath; 98 OUString sWritablePath; 99 100 explicit PathUserData_Impl( sal_uInt16 nId ) : 101 nRealId( nId ), eState( SfxItemState::UNKNOWN ) {} 102 }; 103 104 struct Handle2CfgNameMapping_Impl 105 { 106 sal_uInt16 m_nHandle; 107 const char* m_pCfgName; 108 }; 109 110 static Handle2CfgNameMapping_Impl const Hdl2CfgMap_Impl[] = 111 { 112 { SvtPathOptions::PATH_AUTOCORRECT, "AutoCorrect" }, 113 { SvtPathOptions::PATH_AUTOTEXT, "AutoText" }, 114 { SvtPathOptions::PATH_BACKUP, "Backup" }, 115 { SvtPathOptions::PATH_GALLERY, "Gallery" }, 116 { SvtPathOptions::PATH_GRAPHIC, "Graphic" }, 117 { SvtPathOptions::PATH_TEMP, "Temp" }, 118 { SvtPathOptions::PATH_TEMPLATE, "Template" }, 119 { SvtPathOptions::PATH_WORK, "Work" }, 120 { SvtPathOptions::PATH_DICTIONARY, "Dictionary" }, 121 { SvtPathOptions::PATH_CLASSIFICATION, "Classification" }, 122 #if OSL_DEBUG_LEVEL > 1 123 { SvtPathOptions::PATH_LINGUISTIC, "Linguistic" }, 124 #endif 125 { USHRT_MAX, nullptr } 126 }; 127 128 static OUString getCfgName_Impl( sal_uInt16 _nHandle ) 129 { 130 OUString sCfgName; 131 sal_uInt16 nIndex = 0; 132 while ( Hdl2CfgMap_Impl[ nIndex ].m_nHandle != USHRT_MAX ) 133 { 134 if ( Hdl2CfgMap_Impl[ nIndex ].m_nHandle == _nHandle ) 135 { 136 // config name found 137 sCfgName = OUString::createFromAscii( Hdl2CfgMap_Impl[ nIndex ].m_pCfgName ); 138 break; 139 } 140 ++nIndex; 141 } 142 143 return sCfgName; 144 } 145 146 #define MULTIPATH_DELIMITER ';' 147 148 static OUString Convert_Impl( const OUString& rValue ) 149 { 150 OUString aReturn; 151 if (rValue.isEmpty()) 152 return aReturn; 153 154 sal_Int32 nPos = 0; 155 156 for (;;) 157 { 158 OUString aValue = rValue.getToken( 0, MULTIPATH_DELIMITER, nPos ); 159 INetURLObject aObj( aValue ); 160 if ( aObj.GetProtocol() == INetProtocol::File ) 161 aReturn += aObj.PathToFileName(); 162 if ( nPos < 0 ) 163 break; 164 aReturn += OUStringLiteral1(MULTIPATH_DELIMITER); 165 } 166 167 return aReturn; 168 } 169 170 // functions ------------------------------------------------------------- 171 172 bool IsMultiPath_Impl( const sal_uInt16 nIndex ) 173 { 174 #if OSL_DEBUG_LEVEL > 1 175 return ( SvtPathOptions::PATH_AUTOCORRECT == nIndex || 176 SvtPathOptions::PATH_AUTOTEXT == nIndex || 177 SvtPathOptions::PATH_BASIC == nIndex || 178 SvtPathOptions::PATH_GALLERY == nIndex || 179 SvtPathOptions::PATH_TEMPLATE == nIndex ); 180 #else 181 return ( SvtPathOptions::PATH_AUTOCORRECT == nIndex || 182 SvtPathOptions::PATH_AUTOTEXT == nIndex || 183 SvtPathOptions::PATH_BASIC == nIndex || 184 SvtPathOptions::PATH_GALLERY == nIndex || 185 SvtPathOptions::PATH_TEMPLATE == nIndex || 186 SvtPathOptions::PATH_LINGUISTIC == nIndex || 187 SvtPathOptions::PATH_DICTIONARY == nIndex ); 188 #endif 189 } 190 191 // class SvxPathTabPage -------------------------------------------------- 192 193 SvxPathTabPage::SvxPathTabPage(vcl::Window* pParent, const SfxItemSet& rSet) 194 : SfxTabPage( pParent, "OptPathsPage", "cui/ui/optpathspage.ui", &rSet) 195 , pImpl( new OptPath_Impl(get<FixedImage>("lock")->GetImage(), 196 get<FixedText>("editpaths")->GetText()) ) 197 , xDialogListener ( new ::svt::DialogClosedListener() ) 198 { 199 get(m_pStandardBtn, "default"); 200 get(m_pPathBtn, "edit"); 201 get(m_pPathCtrl, "paths"); 202 203 m_pStandardBtn->SetClickHdl(LINK(this, SvxPathTabPage, StandardHdl_Impl)); 204 m_pPathBtn->SetClickHdl( LINK( this, SvxPathTabPage, PathHdl_Impl ) ); 205 206 Size aControlSize(236 , 147); 207 aControlSize = LogicToPixel(aControlSize, MapMode(MapUnit::MapAppFont)); 208 m_pPathCtrl->set_width_request(aControlSize.Width()); 209 m_pPathCtrl->set_height_request(aControlSize.Height()); 210 WinBits nBits = WB_SORT | WB_HSCROLL | WB_CLIPCHILDREN | WB_TABSTOP; 211 pPathBox = VclPtr<svx::OptHeaderTabListBox>::Create( *m_pPathCtrl, nBits ); 212 213 HeaderBar &rBar = pPathBox->GetTheHeaderBar(); 214 rBar.SetSelectHdl( LINK( this, SvxPathTabPage, HeaderSelect_Impl ) ); 215 rBar.SetEndDragHdl( LINK( this, SvxPathTabPage, HeaderEndDrag_Impl ) ); 216 217 rBar.InsertItem( ITEMID_TYPE, get<FixedText>("type")->GetText(), 218 0, 219 HeaderBarItemBits::LEFT | HeaderBarItemBits::VCENTER | HeaderBarItemBits::CLICKABLE | HeaderBarItemBits::UPARROW ); 220 rBar.InsertItem( ITEMID_PATH, get<FixedText>("path")->GetText(), 221 0, 222 HeaderBarItemBits::LEFT | HeaderBarItemBits::VCENTER ); 223 224 long nWidth1 = rBar.GetTextWidth(rBar.GetItemText(ITEMID_TYPE)); 225 long nWidth2 = rBar.GetTextWidth(rBar.GetItemText(ITEMID_PATH)); 226 227 long aTabs[] = {0, 0, 0}; 228 aTabs[1] = nWidth1 + 12; 229 aTabs[2] = aTabs[1] + nWidth2 + 12; 230 pPathBox->SetTabs(SAL_N_ELEMENTS(aTabs), aTabs, MapUnit::MapPixel); 231 232 pPathBox->SetDoubleClickHdl( LINK( this, SvxPathTabPage, DoubleClickPathHdl_Impl ) ); 233 pPathBox->SetSelectHdl( LINK( this, SvxPathTabPage, PathSelect_Impl ) ); 234 pPathBox->SetSelectionMode( SelectionMode::Multiple ); 235 pPathBox->SetHighlightRange(); 236 237 xDialogListener->SetDialogClosedLink( LINK( this, SvxPathTabPage, DialogClosedHdl ) ); 238 } 239 240 241 SvxPathTabPage::~SvxPathTabPage() 242 { 243 disposeOnce(); 244 } 245 246 void SvxPathTabPage::dispose() 247 { 248 if ( pPathBox ) 249 { 250 for ( sal_uLong i = 0; i < pPathBox->GetEntryCount(); ++i ) 251 delete static_cast<PathUserData_Impl*>(pPathBox->GetEntry(i)->GetUserData()); 252 pPathBox.disposeAndClear(); 253 } 254 pImpl.reset(); 255 m_pPathCtrl.clear(); 256 m_pStandardBtn.clear(); 257 m_pPathBtn.clear(); 258 SfxTabPage::dispose(); 259 } 260 261 VclPtr<SfxTabPage> SvxPathTabPage::Create( TabPageParent pParent, 262 const SfxItemSet* rAttrSet ) 263 { 264 return VclPtr<SvxPathTabPage>::Create( pParent.pParent, *rAttrSet ); 265 } 266 267 bool SvxPathTabPage::FillItemSet( SfxItemSet* ) 268 { 269 for ( sal_uLong i = 0; i < pPathBox->GetEntryCount(); ++i ) 270 { 271 PathUserData_Impl* pPathImpl = static_cast<PathUserData_Impl*>(pPathBox->GetEntry(i)->GetUserData()); 272 sal_uInt16 nRealId = pPathImpl->nRealId; 273 if ( pPathImpl->eState == SfxItemState::SET ) 274 SetPathList( nRealId, pPathImpl->sUserPath, pPathImpl->sWritablePath ); 275 } 276 return true; 277 } 278 279 void SvxPathTabPage::Reset( const SfxItemSet* ) 280 { 281 pPathBox->Clear(); 282 283 HeaderBar &rBar = pPathBox->GetTheHeaderBar(); 284 long nWidth1 = rBar.GetTextWidth(rBar.GetItemText(1)); 285 long nWidth2 = rBar.GetTextWidth(rBar.GetItemText(2)); 286 287 for( sal_uInt16 i = 0; i <= sal_uInt16(SvtPathOptions::PATH_CLASSIFICATION); ++i ) 288 { 289 // only writer uses autotext 290 if ( i == SvtPathOptions::PATH_AUTOTEXT 291 && !SvtModuleOptions().IsModuleInstalled( SvtModuleOptions::EModule::WRITER ) ) 292 continue; 293 294 const char* pId = nullptr; 295 296 switch (i) 297 { 298 case SvtPathOptions::PATH_AUTOCORRECT: 299 pId = RID_SVXSTR_KEY_AUTOCORRECT_DIR; 300 break; 301 case SvtPathOptions::PATH_AUTOTEXT: 302 pId = RID_SVXSTR_KEY_GLOSSARY_PATH; 303 break; 304 case SvtPathOptions::PATH_BACKUP: 305 pId = RID_SVXSTR_KEY_BACKUP_PATH; 306 break; 307 case SvtPathOptions::PATH_GALLERY: 308 pId = RID_SVXSTR_KEY_GALLERY_DIR; 309 break; 310 case SvtPathOptions::PATH_GRAPHIC: 311 pId = RID_SVXSTR_KEY_GRAPHICS_PATH; 312 break; 313 case SvtPathOptions::PATH_TEMP: 314 pId = RID_SVXSTR_KEY_TEMP_PATH; 315 break; 316 case SvtPathOptions::PATH_TEMPLATE: 317 pId = RID_SVXSTR_KEY_TEMPLATE_PATH; 318 break; 319 case SvtPathOptions::PATH_DICTIONARY: 320 pId = RID_SVXSTR_KEY_DICTIONARY_PATH; 321 break; 322 case SvtPathOptions::PATH_CLASSIFICATION: 323 pId = RID_SVXSTR_KEY_CLASSIFICATION_PATH; 324 break; 325 #if OSL_DEBUG_LEVEL > 1 326 case SvtPathOptions::PATH_LINGUISTIC: 327 pId = RID_SVXSTR_KEY_LINGUISTIC_DIR; 328 break; 329 #endif 330 case SvtPathOptions::PATH_WORK: 331 pId = RID_SVXSTR_KEY_WORK_PATH; 332 break; 333 } 334 335 if (pId) 336 { 337 OUString aStr(CuiResId(pId)); 338 339 nWidth1 = std::max(nWidth1, pPathBox->GetTextWidth(aStr)); 340 aStr += "\t"; 341 OUString sInternal, sUser, sWritable; 342 bool bReadOnly = false; 343 GetPathList( i, sInternal, sUser, sWritable, bReadOnly ); 344 OUString sTmpPath = sUser; 345 if ( !sTmpPath.isEmpty() && !sWritable.isEmpty() ) 346 sTmpPath += OUStringLiteral1(MULTIPATH_DELIMITER); 347 sTmpPath += sWritable; 348 const OUString aValue = Convert_Impl( sTmpPath ); 349 nWidth2 = std::max(nWidth2, pPathBox->GetTextWidth(aValue)); 350 aStr += aValue; 351 SvTreeListEntry* pEntry = pPathBox->InsertEntry( aStr ); 352 if ( bReadOnly ) 353 { 354 pPathBox->SetCollapsedEntryBmp( pEntry, pImpl->m_aLockImage ); 355 } 356 PathUserData_Impl* pPathImpl = new PathUserData_Impl(i); 357 pPathImpl->sUserPath = sUser; 358 pPathImpl->sWritablePath = sWritable; 359 pEntry->SetUserData( pPathImpl ); 360 } 361 362 } 363 364 long aTabs[] = {0, 0, 0}; 365 aTabs[1] = nWidth1 + 12; 366 aTabs[2] = aTabs[1] + nWidth2 + 12; 367 pPathBox->SetTabs(SAL_N_ELEMENTS(aTabs), aTabs, MapUnit::MapPixel); 368 369 PathSelect_Impl( nullptr ); 370 } 371 372 void SvxPathTabPage::FillUserData() 373 { 374 HeaderBar &rBar = pPathBox->GetTheHeaderBar(); 375 376 OUString aUserData = OUString::number( rBar.GetItemSize( ITEMID_TYPE ) ) + ";"; 377 HeaderBarItemBits nBits = rBar.GetItemBits( ITEMID_TYPE ); 378 bool bUp = ( ( nBits & HeaderBarItemBits::UPARROW ) == HeaderBarItemBits::UPARROW ); 379 aUserData += bUp ? OUString("1") : OUString("0"); 380 SetUserData( aUserData ); 381 } 382 383 IMPL_LINK_NOARG(SvxPathTabPage, PathSelect_Impl, SvTreeListBox*, void) 384 { 385 sal_uInt16 nSelCount = 0; 386 SvTreeListEntry* pEntry = pPathBox->FirstSelected(); 387 388 //the entry image indicates whether the path is write protected 389 Image aEntryImage; 390 if(pEntry) 391 aEntryImage = SvTreeListBox::GetCollapsedEntryBmp( pEntry ); 392 bool bEnable = !aEntryImage; 393 while ( pEntry && ( nSelCount < 2 ) ) 394 { 395 nSelCount++; 396 pEntry = pPathBox->NextSelected( pEntry ); 397 } 398 399 m_pPathBtn->Enable( 1 == nSelCount && bEnable); 400 m_pStandardBtn->Enable( nSelCount > 0 && bEnable); 401 } 402 403 IMPL_LINK_NOARG(SvxPathTabPage, StandardHdl_Impl, Button*, void) 404 { 405 SvTreeListEntry* pEntry = pPathBox->FirstSelected(); 406 while ( pEntry ) 407 { 408 PathUserData_Impl* pPathImpl = static_cast<PathUserData_Impl*>(pEntry->GetUserData()); 409 OUString aOldPath = pImpl->m_aDefOpt.GetDefaultPath( pPathImpl->nRealId ); 410 411 if ( !aOldPath.isEmpty() ) 412 { 413 OUString sInternal, sUser, sWritable, sTemp; 414 bool bReadOnly = false; 415 GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); 416 417 sal_Int32 nOldPos = 0; 418 do 419 { 420 bool bFound = false; 421 const OUString sOnePath = aOldPath.getToken( 0, MULTIPATH_DELIMITER, nOldPos ); 422 if ( !sInternal.isEmpty() ) 423 { 424 sal_Int32 nInternalPos = 0; 425 do 426 { 427 if ( sInternal.getToken( 0, MULTIPATH_DELIMITER, nInternalPos ) == sOnePath ) 428 bFound = true; 429 } 430 while ( !bFound && nInternalPos >= 0 ); 431 } 432 if ( !bFound ) 433 { 434 if ( !sTemp.isEmpty() ) 435 sTemp += OUStringLiteral1(MULTIPATH_DELIMITER); 436 sTemp += sOnePath; 437 } 438 } 439 while ( nOldPos >= 0 ); 440 441 OUString sUserPath, sWritablePath; 442 if ( !sTemp.isEmpty() ) 443 { 444 sal_Int32 nNextPos = 0; 445 for (;;) 446 { 447 const OUString sToken = sTemp.getToken( 0, MULTIPATH_DELIMITER, nNextPos ); 448 if ( nNextPos<0 ) 449 { 450 // Last token need a different handling 451 sWritablePath = sToken; 452 break; 453 } 454 if ( !sUserPath.isEmpty() ) 455 sUserPath += OUStringLiteral1(MULTIPATH_DELIMITER); 456 sUserPath += sToken; 457 } 458 } 459 pPathBox->SetEntryText( Convert_Impl( sTemp ), pEntry, 1 ); 460 pPathImpl->eState = SfxItemState::SET; 461 pPathImpl->sUserPath = sUserPath; 462 pPathImpl->sWritablePath = sWritablePath; 463 } 464 pEntry = pPathBox->NextSelected( pEntry ); 465 } 466 } 467 468 469 void SvxPathTabPage::ChangeCurrentEntry( const OUString& _rFolder ) 470 { 471 SvTreeListEntry* pEntry = pPathBox->GetCurEntry(); 472 if ( !pEntry ) 473 { 474 SAL_WARN( "cui.options", "SvxPathTabPage::ChangeCurrentEntry(): no entry" ); 475 return; 476 } 477 478 OUString sInternal, sUser, sWritable; 479 PathUserData_Impl* pPathImpl = static_cast<PathUserData_Impl*>(pEntry->GetUserData()); 480 bool bReadOnly = false; 481 GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); 482 sUser = pPathImpl->sUserPath; 483 sWritable = pPathImpl->sWritablePath; 484 485 // old path is an URL? 486 INetURLObject aObj( sWritable ); 487 bool bURL = ( aObj.GetProtocol() != INetProtocol::NotValid ); 488 INetURLObject aNewObj( _rFolder ); 489 aNewObj.removeFinalSlash(); 490 491 // then the new path also an URL else system path 492 OUString sNewPathStr = bURL ? _rFolder : aNewObj.getFSysPath( FSysStyle::Detect ); 493 494 bool bChanged = 495 #ifdef UNX 496 // Unix is case sensitive 497 ( sNewPathStr != sWritable ); 498 #else 499 !sNewPathStr.equalsIgnoreAsciiCase( sWritable ); 500 #endif 501 502 if ( bChanged ) 503 { 504 pPathBox->SetEntryText( Convert_Impl( sNewPathStr ), pEntry, 1 ); 505 sal_uInt16 nPos = static_cast<sal_uInt16>(pPathBox->GetModel()->GetAbsPos( pEntry )); 506 pPathImpl = static_cast<PathUserData_Impl*>(pPathBox->GetEntry(nPos)->GetUserData()); 507 pPathImpl->eState = SfxItemState::SET; 508 pPathImpl->sWritablePath = sNewPathStr; 509 if ( SvtPathOptions::PATH_WORK == pPathImpl->nRealId ) 510 { 511 // Remove view options entry so the new work path 512 // will be used for the next open dialog. 513 SvtViewOptions aDlgOpt( EViewType::Dialog, IODLG_CONFIGNAME ); 514 aDlgOpt.Delete(); 515 // Reset also last used dir in the sfx application instance 516 SfxApplication *pSfxApp = SfxGetpApp(); 517 pSfxApp->ResetLastDir(); 518 519 // Set configuration flag to notify file picker that it's necessary 520 // to take over the path provided. 521 std::shared_ptr< comphelper::ConfigurationChanges > batch( 522 comphelper::ConfigurationChanges::create()); 523 officecfg::Office::Common::Path::Info::WorkPathChanged::set( 524 true, batch); 525 batch->commit(); 526 } 527 } 528 } 529 530 531 IMPL_LINK_NOARG(SvxPathTabPage, DoubleClickPathHdl_Impl, SvTreeListBox*, bool) 532 { 533 PathHdl_Impl(nullptr); 534 return false; 535 } 536 537 IMPL_LINK_NOARG(SvxPathTabPage, PathHdl_Impl, Button*, void) 538 { 539 SvTreeListEntry* pEntry = pPathBox->GetCurEntry(); 540 sal_uInt16 nPos = ( pEntry != nullptr ) ? static_cast<PathUserData_Impl*>(pEntry->GetUserData())->nRealId : 0; 541 OUString sInternal, sUser, sWritable; 542 bool bPickFile = false; 543 if ( pEntry ) 544 { 545 PathUserData_Impl* pPathImpl = static_cast<PathUserData_Impl*>(pEntry->GetUserData()); 546 bool bReadOnly = false; 547 GetPathList( pPathImpl->nRealId, sInternal, sUser, sWritable, bReadOnly ); 548 sUser = pPathImpl->sUserPath; 549 sWritable = pPathImpl->sWritablePath; 550 bPickFile = pPathImpl->nRealId == SvtPathOptions::PATH_CLASSIFICATION; 551 } 552 553 if(pEntry && !(!SvTreeListBox::GetCollapsedEntryBmp(pEntry))) 554 return; 555 556 if ( IsMultiPath_Impl( nPos ) ) 557 { 558 SvxAbstractDialogFactory* pFact = SvxAbstractDialogFactory::Create(); 559 ScopedVclPtr<AbstractSvxMultiPathDialog> pMultiDlg( 560 pFact->CreateSvxMultiPathDialog( this )); 561 562 OUString sPath( sUser ); 563 if ( !sPath.isEmpty() ) 564 sPath += OUStringLiteral1(MULTIPATH_DELIMITER); 565 sPath += sWritable; 566 pMultiDlg->SetPath( sPath ); 567 568 const OUString sPathName = SvTabListBox::GetEntryText( pEntry, 0 ); 569 const OUString sNewTitle = pImpl->m_sMultiPathDlg.replaceFirst( VAR_ONE, sPathName ); 570 pMultiDlg->SetTitle( sNewTitle ); 571 572 if ( pMultiDlg->Execute() == RET_OK && pEntry ) 573 { 574 sUser.clear(); 575 sWritable.clear(); 576 OUString sFullPath; 577 OUString sNewPath = pMultiDlg->GetPath(); 578 if ( !sNewPath.isEmpty() ) 579 { 580 sal_Int32 nNextPos = 0; 581 for (;;) 582 { 583 const OUString sToken(sNewPath.getToken( 0, MULTIPATH_DELIMITER, nNextPos )); 584 if ( nNextPos<0 ) 585 { 586 // Last token need a different handling 587 sWritable = sToken; 588 break; 589 } 590 if ( !sUser.isEmpty() ) 591 sUser += OUStringLiteral1(MULTIPATH_DELIMITER); 592 sUser += sToken; 593 } 594 sFullPath = sUser; 595 if ( !sFullPath.isEmpty() ) 596 sFullPath += OUStringLiteral1(MULTIPATH_DELIMITER); 597 sFullPath += sWritable; 598 } 599 600 pPathBox->SetEntryText( Convert_Impl( sFullPath ), pEntry, 1 ); 601 // save modified flag 602 PathUserData_Impl* pPathImpl = static_cast<PathUserData_Impl*>(pEntry->GetUserData()); 603 pPathImpl->eState = SfxItemState::SET; 604 pPathImpl->sUserPath = sUser; 605 pPathImpl->sWritablePath = sWritable; 606 } 607 } 608 else if (pEntry && !bPickFile) 609 { 610 try 611 { 612 Reference < XComponentContext > xContext( ::comphelper::getProcessComponentContext() ); 613 xFolderPicker = FolderPicker::create(xContext); 614 615 INetURLObject aURL( sWritable, INetProtocol::File ); 616 xFolderPicker->setDisplayDirectory( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) ); 617 618 Reference< XAsynchronousExecutableDialog > xAsyncDlg( xFolderPicker, UNO_QUERY ); 619 if ( xAsyncDlg.is() ) 620 xAsyncDlg->startExecuteModal( xDialogListener.get() ); 621 else 622 { 623 short nRet = xFolderPicker->execute(); 624 if (ExecutableDialogResults::OK != nRet) 625 return; 626 627 OUString sFolder(xFolderPicker->getDirectory()); 628 ChangeCurrentEntry(sFolder); 629 } 630 } 631 catch( Exception& ) 632 { 633 SAL_WARN( "cui.options", "SvxPathTabPage::PathHdl_Impl: exception from folder picker" ); 634 } 635 } 636 else if (pEntry) 637 { 638 try 639 { 640 uno::Reference<uno::XComponentContext> xComponentContext(comphelper::getProcessComponentContext()); 641 uno::Reference<ui::dialogs::XFilePicker3> xFilePicker = ui::dialogs::FilePicker::createWithMode(xComponentContext, ui::dialogs::TemplateDescription::FILEOPEN_SIMPLE); 642 xFilePicker->appendFilter(OUString(), "*.xml"); 643 if (xFilePicker->execute() == ui::dialogs::ExecutableDialogResults::OK) 644 { 645 uno::Sequence<OUString> aPathSeq(xFilePicker->getSelectedFiles()); 646 ChangeCurrentEntry(aPathSeq[0]); 647 } 648 } 649 catch (const uno::Exception&) 650 { 651 DBG_UNHANDLED_EXCEPTION("cui.options", "exception from file picker"); 652 } 653 } 654 } 655 656 657 IMPL_LINK( SvxPathTabPage, HeaderSelect_Impl, HeaderBar*, pBar, void ) 658 { 659 if (!pBar || pBar->GetCurItemId() != ITEMID_TYPE) 660 return; 661 662 HeaderBarItemBits nBits = pBar->GetItemBits(ITEMID_TYPE); 663 bool bUp = ( ( nBits & HeaderBarItemBits::UPARROW ) == HeaderBarItemBits::UPARROW ); 664 SvSortMode eMode = SortAscending; 665 666 if ( bUp ) 667 { 668 nBits &= ~HeaderBarItemBits::UPARROW; 669 nBits |= HeaderBarItemBits::DOWNARROW; 670 eMode = SortDescending; 671 } 672 else 673 { 674 nBits &= ~HeaderBarItemBits::DOWNARROW; 675 nBits |= HeaderBarItemBits::UPARROW; 676 } 677 pBar->SetItemBits( ITEMID_TYPE, nBits ); 678 SvTreeList* pModel = pPathBox->GetModel(); 679 pModel->SetSortMode( eMode ); 680 pModel->Resort(); 681 } 682 683 684 IMPL_LINK( SvxPathTabPage, HeaderEndDrag_Impl, HeaderBar*, pBar, void ) 685 { 686 if (!pBar || !pBar->GetCurItemId()) 687 return; 688 689 if ( !pBar->IsItemMode() ) 690 { 691 Size aSz; 692 sal_uInt16 nTabs = pBar->GetItemCount(); 693 long nTmpSz = 0; 694 long nWidth = pBar->GetItemSize(ITEMID_TYPE); 695 long nBarWidth = pBar->GetSizePixel().Width(); 696 697 if(nWidth < TAB_WIDTH_MIN) 698 pBar->SetItemSize( ITEMID_TYPE, TAB_WIDTH_MIN); 699 else if ( ( nBarWidth - nWidth ) < TAB_WIDTH_MIN ) 700 pBar->SetItemSize( ITEMID_TYPE, nBarWidth - TAB_WIDTH_MIN ); 701 702 for ( sal_uInt16 i = 1; i <= nTabs; ++i ) 703 { 704 long _nWidth = pBar->GetItemSize(i); 705 aSz.setWidth( _nWidth + nTmpSz ); 706 nTmpSz += _nWidth; 707 pPathBox->SetTab( i, PixelToLogic( aSz, MapMode(MapUnit::MapAppFont) ).Width() ); 708 } 709 } 710 } 711 712 IMPL_LINK( SvxPathTabPage, DialogClosedHdl, DialogClosedEvent*, pEvt, void ) 713 { 714 if (RET_OK == pEvt->DialogResult) 715 { 716 assert(xFolderPicker.is() && "SvxPathTabPage::DialogClosedHdl(): no folder picker"); 717 OUString sURL = xFolderPicker->getDirectory(); 718 ChangeCurrentEntry( sURL ); 719 } 720 } 721 722 void SvxPathTabPage::GetPathList( 723 sal_uInt16 _nPathHandle, OUString& _rInternalPath, 724 OUString& _rUserPath, OUString& _rWritablePath, bool& _rReadOnly ) 725 { 726 OUString sCfgName = getCfgName_Impl( _nPathHandle ); 727 728 try 729 { 730 // load PathSettings service if necessary 731 if ( !pImpl->m_xPathSettings.is() ) 732 { 733 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); 734 pImpl->m_xPathSettings = css::util::thePathSettings::get( xContext ); 735 } 736 737 // load internal paths 738 Any aAny = pImpl->m_xPathSettings->getPropertyValue( 739 sCfgName + POSTFIX_INTERNAL); 740 Sequence< OUString > aPathSeq; 741 if ( aAny >>= aPathSeq ) 742 { 743 long i, nCount = aPathSeq.getLength(); 744 const OUString* pPaths = aPathSeq.getConstArray(); 745 746 for ( i = 0; i < nCount; ++i ) 747 { 748 if ( !_rInternalPath.isEmpty() ) 749 _rInternalPath += ";"; 750 _rInternalPath += pPaths[i]; 751 } 752 } 753 // load user paths 754 aAny = pImpl->m_xPathSettings->getPropertyValue( 755 sCfgName + POSTFIX_USER); 756 if ( aAny >>= aPathSeq ) 757 { 758 long i, nCount = aPathSeq.getLength(); 759 const OUString* pPaths = aPathSeq.getConstArray(); 760 761 for ( i = 0; i < nCount; ++i ) 762 { 763 if ( !_rUserPath.isEmpty() ) 764 _rUserPath += ";"; 765 _rUserPath += pPaths[i]; 766 } 767 } 768 // then the writable path 769 aAny = pImpl->m_xPathSettings->getPropertyValue( 770 sCfgName + POSTFIX_WRITABLE); 771 OUString sWritablePath; 772 if ( aAny >>= sWritablePath ) 773 _rWritablePath = sWritablePath; 774 775 // and the readonly flag 776 Reference< XPropertySetInfo > xInfo = pImpl->m_xPathSettings->getPropertySetInfo(); 777 Property aProp = xInfo->getPropertyByName(sCfgName); 778 _rReadOnly = ( ( aProp.Attributes & PropertyAttribute::READONLY ) == PropertyAttribute::READONLY ); 779 } 780 catch( const Exception& ) 781 { 782 OSL_FAIL( "SvxPathTabPage::GetPathList(): caught an exception!" ); 783 } 784 } 785 786 787 void SvxPathTabPage::SetPathList( 788 sal_uInt16 _nPathHandle, const OUString& _rUserPath, const OUString& _rWritablePath ) 789 { 790 OUString sCfgName = getCfgName_Impl( _nPathHandle ); 791 792 try 793 { 794 // load PathSettings service if necessary 795 if ( !pImpl->m_xPathSettings.is() ) 796 { 797 Reference< XComponentContext > xContext = comphelper::getProcessComponentContext(); 798 pImpl->m_xPathSettings = css::util::thePathSettings::get( xContext ); 799 } 800 801 // save user paths 802 const sal_Int32 nCount = comphelper::string::getTokenCount(_rUserPath, MULTIPATH_DELIMITER); 803 Sequence< OUString > aPathSeq( nCount ); 804 OUString* pArray = aPathSeq.getArray(); 805 sal_Int32 nPos = 0; 806 for ( sal_Int32 i = 0; i < nCount; ++i ) 807 pArray[i] = _rUserPath.getToken( 0, MULTIPATH_DELIMITER, nPos ); 808 Any aValue( aPathSeq ); 809 pImpl->m_xPathSettings->setPropertyValue( 810 sCfgName + POSTFIX_USER, aValue); 811 812 // then the writable path 813 aValue <<= _rWritablePath; 814 pImpl->m_xPathSettings->setPropertyValue( 815 sCfgName + POSTFIX_WRITABLE, aValue); 816 } 817 catch( const Exception& e ) 818 { 819 SAL_WARN("cui.options", "caught: " << e); 820 } 821 } 822 823 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 824
