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 <memory> 21 22 #include <vcl/commandinfoprovider.hxx> 23 #include <vcl/event.hxx> 24 #include <vcl/help.hxx> 25 #include <vcl/menu.hxx> 26 #include <vcl/settings.hxx> 27 #include <vcl/svapp.hxx> 28 #include <svl/intitem.hxx> 29 #include <svl/stritem.hxx> 30 #include <svl/style.hxx> 31 #include <comphelper/processfactory.hxx> 32 #include <comphelper/sequenceashashmap.hxx> 33 #include <unotools/intlwrapper.hxx> 34 #include <unotools/collatorwrapper.hxx> 35 #include <com/sun/star/beans/PropertyValue.hpp> 36 #include <com/sun/star/frame/ModuleManager.hpp> 37 #include <com/sun/star/frame/UnknownModuleException.hpp> 38 #include <officecfg/Office/Common.hxx> 39 40 #include <sal/log.hxx> 41 #include <osl/diagnose.h> 42 #include <sfx2/app.hxx> 43 #include <sfx2/dispatch.hxx> 44 #include <sfx2/bindings.hxx> 45 #include <sfx2/templdlg.hxx> 46 #include <templdgi.hxx> 47 #include <tplcitem.hxx> 48 #include <sfx2/styfitem.hxx> 49 #include <sfx2/objsh.hxx> 50 #include <sfx2/viewsh.hxx> 51 #include <sfx2/newstyle.hxx> 52 #include <sfx2/tplpitem.hxx> 53 #include <sfx2/sfxresid.hxx> 54 55 #include <sfx2/sfxsids.hrc> 56 #include <sfx2/strings.hrc> 57 #include <sfx2/docfac.hxx> 58 #include <sfx2/module.hxx> 59 #include <helpids.h> 60 #include <bitmaps.hlst> 61 #include <sfx2/viewfrm.hxx> 62 63 #include <vcl/svlbitm.hxx> 64 #include <vcl/treelistentry.hxx> 65 #include <vcl/viewdataentry.hxx> 66 #include <comphelper/string.hxx> 67 68 #include <sfx2/StyleManager.hxx> 69 #include <sfx2/StylePreviewRenderer.hxx> 70 71 #define STD_ENTRY_HEIGHT 17 72 73 using namespace css; 74 using namespace css::beans; 75 using namespace css::frame; 76 using namespace css::uno; 77 78 namespace 79 { 80 81 class StyleLBoxString : public SvLBoxString 82 { 83 SfxStyleFamily const meStyleFamily; 84 SvViewDataItem* mpViewData; 85 86 public: 87 StyleLBoxString(const OUString& sText, 88 const SfxStyleFamily& eStyleFamily); 89 90 virtual void Paint(const Point& aPos, 91 SvTreeListBox& rDevice, 92 vcl::RenderContext& rRenderContext, 93 const SvViewDataEntry* pView, 94 const SvTreeListEntry& rEntry) override; 95 96 virtual void InitViewData(SvTreeListBox* pView, 97 SvTreeListEntry* pEntry, 98 SvViewDataItem* pViewData = nullptr) override; 99 }; 100 101 102 StyleLBoxString::StyleLBoxString(const OUString& sText, const SfxStyleFamily& eStyleFamily) 103 : SvLBoxString(sText) 104 , meStyleFamily(eStyleFamily) 105 , mpViewData(nullptr) 106 {} 107 108 void StyleLBoxString::InitViewData(SvTreeListBox* pView, SvTreeListEntry* pEntry, SvViewDataItem* pViewData) 109 { 110 if (!pViewData) 111 { 112 pViewData = pView->GetViewDataItem(pEntry, this); 113 } 114 mpViewData = pViewData; 115 } 116 117 void StyleLBoxString::Paint( 118 const Point& aPos, SvTreeListBox& rDevice, vcl::RenderContext& rRenderContext, 119 const SvViewDataEntry* pView, const SvTreeListEntry& rEntry) 120 { 121 bool bPainted = false; 122 123 SfxObjectShell* pShell = SfxObjectShell::Current(); 124 sfx2::StyleManager* pStyleManager = pShell? pShell->GetStyleManager(): nullptr; 125 126 if (pStyleManager) 127 { 128 SfxStyleSheetBase* pStyleSheet = pStyleManager->Search(GetText(), meStyleFamily); 129 130 if (pStyleSheet) 131 { 132 sal_Int32 nSize = 32 * rRenderContext.GetDPIScaleFactor(); 133 std::unique_ptr<sfx2::StylePreviewRenderer> pStylePreviewRenderer( 134 pStyleManager->CreateStylePreviewRenderer(rRenderContext, pStyleSheet, nSize)); 135 136 if (pStylePreviewRenderer) 137 { 138 if (pStylePreviewRenderer->recalculate()) 139 { 140 Size aSize(pStylePreviewRenderer->getRenderSize()); 141 mpViewData->mnWidth = aSize.Width(); 142 mpViewData->mnHeight = aSize.Height(); 143 } 144 else 145 { 146 SvLBoxString::InitViewData( &rDevice, const_cast<SvTreeListEntry*>(&rEntry), mpViewData); 147 } 148 149 tools::Rectangle aPaintRectangle = pView->GetPaintRectangle(); 150 bPainted = pStylePreviewRenderer->render(aPaintRectangle); 151 } 152 } 153 } 154 155 if (!bPainted) 156 { 157 rRenderContext.DrawText(aPos, GetText()); 158 } 159 } 160 161 } // end anonymous namespace 162 163 // Window is now created dynamically. So here margins, etc. 164 165 #define SFX_TEMPLDLG_HFRAME 3 166 #define SFX_TEMPLDLG_VTOPFRAME 3 167 168 #define SFX_TEMPLDLG_VBOTFRAME 3 169 #define SFX_TEMPLDLG_MIDHSPACE 3 170 #define SFX_TEMPLDLG_MIDVSPACE 3 171 #define SFX_TEMPLDLG_FILTERHEIGHT 100 172 173 // filter box has maximum 14 entries visible 174 #define MAX_FILTER_ENTRIES 14 175 176 177 class SfxCommonTemplateDialog_Impl::DeletionWatcher 178 { 179 typedef void (DeletionWatcher::* bool_type)(); 180 181 public: 182 explicit DeletionWatcher(SfxCommonTemplateDialog_Impl& rDialog) 183 : m_pDialog(&rDialog) 184 , m_pPrevious(m_pDialog->impl_setDeletionWatcher(this)) 185 { 186 } 187 188 ~DeletionWatcher() 189 { 190 if (m_pDialog) 191 m_pDialog->impl_setDeletionWatcher(m_pPrevious); 192 } 193 194 DeletionWatcher(const DeletionWatcher&) = delete; 195 DeletionWatcher& operator=(const DeletionWatcher&) = delete; 196 197 // Signal that the dialog was deleted 198 void signal() 199 { 200 m_pDialog = nullptr; 201 if (m_pPrevious) 202 m_pPrevious->signal(); 203 } 204 205 // Return true if the dialog was deleted 206 operator bool_type() const 207 { 208 return m_pDialog ? nullptr : &DeletionWatcher::signal; 209 } 210 211 private: 212 SfxCommonTemplateDialog_Impl* m_pDialog; 213 DeletionWatcher *const m_pPrevious; /// let's add more epicycles! 214 }; 215 216 void DropListBox_Impl::MouseButtonDown( const MouseEvent& rMEvt ) 217 { 218 nModifier = rMEvt.GetModifier(); 219 220 bool bHitEmptySpace = ( nullptr == GetEntry( rMEvt.GetPosPixel(), true ) ); 221 if( bHitEmptySpace && ( rMEvt.GetClicks() == 2 ) && rMEvt.IsMod1() ) 222 Control::MouseButtonDown( rMEvt ); 223 else 224 SvTreeListBox::MouseButtonDown( rMEvt ); 225 } 226 227 /** Drop is enabled as long as it is allowed to create a new style by example, i.e. to 228 create a style out of the current selection. 229 */ 230 sal_Int8 DropListBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt ) 231 { 232 if ( IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) ) 233 { 234 // special case: page styles are allowed to create new styles by example 235 // but not allowed to be created by drag and drop 236 if (pDialog->GetActualFamily() == SfxStyleFamily::Page || 237 pDialog->bNewByExampleDisabled) 238 return DND_ACTION_NONE; 239 else 240 return DND_ACTION_COPY; 241 } 242 return SvTreeListBox::AcceptDrop( rEvt ); 243 } 244 245 sal_Int8 DropListBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt ) 246 { 247 sal_Int8 nRet = DND_ACTION_NONE; 248 SfxObjectShell* pDocShell = pDialog->GetObjectShell(); 249 TransferableDataHelper aHelper( rEvt.maDropEvent.Transferable ); 250 sal_uInt32 nFormatCount = aHelper.GetFormatCount(); 251 if ( pDocShell ) 252 { 253 bool bFormatFound = false; 254 255 for ( sal_uInt32 i = 0; i < nFormatCount; ++i ) 256 { 257 SotClipboardFormatId nId = aHelper.GetFormat(i); 258 TransferableObjectDescriptor aDesc; 259 260 if ( aHelper.GetTransferableObjectDescriptor( nId, aDesc ) ) 261 { 262 if ( aDesc.maClassName == pDocShell->GetFactory().GetClassId() ) 263 { 264 PostUserEvent( LINK( this, DropListBox_Impl, OnAsyncExecuteDrop ), nullptr, true ); 265 266 bFormatFound = true; 267 nRet = rEvt.mnAction; 268 break; 269 } 270 } 271 } 272 273 if ( !bFormatFound ) 274 return SvTreeListBox::ExecuteDrop( rEvt ); 275 } 276 277 return nRet; 278 } 279 280 IMPL_LINK_NOARG(DropListBox_Impl, OnAsyncExecuteDrop, void*, void) 281 { 282 pDialog->ActionSelect( SID_STYLE_NEW_BY_EXAMPLE ); 283 } 284 285 bool DropListBox_Impl::EventNotify( NotifyEvent& rNEvt ) 286 { 287 bool bRet = false; 288 if( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) 289 { 290 const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode(); 291 if(!rKeyCode.GetModifier()) 292 { 293 if( pDialog->bCanDel && KEY_DELETE == rKeyCode.GetCode()) 294 { 295 pDialog->DeleteHdl(); 296 bRet = true; 297 } 298 else if( KEY_RETURN == rKeyCode.GetCode()) 299 { 300 GetDoubleClickHdl().Call(this); 301 bRet = true; 302 } 303 } 304 } 305 if(!bRet) 306 bRet = SvTreeListBox::EventNotify( rNEvt ); 307 return bRet; 308 } 309 310 void DropListBox_Impl::RequestHelp(const HelpEvent& rHEvt) 311 { 312 if (rHEvt.GetMode() & HelpEventMode::QUICK) 313 { 314 Point aPos(ScreenToOutputPixel(rHEvt.GetMousePosPixel())); 315 SvTreeListEntry* pEntry = GetEntry(aPos); 316 if (pEntry) 317 { 318 const OUString aTemplName(GetEntryText(pEntry)); 319 OUString sQuickHelpText(aTemplName); 320 321 const SfxStyleFamilyItem* pItem = pDialog->GetFamilyItem_Impl(); 322 SfxStyleSheetBase* pStyle = pDialog->pStyleSheetPool->Find(aTemplName, pItem->GetFamily()); 323 324 if (pStyle && pStyle->IsUsed()) // pStyle is in use in the document? 325 { 326 OUString sUsedBy; 327 if (pStyle->GetFamily() == SfxStyleFamily::Pseudo) 328 { 329 sUsedBy = pStyle->GetUsedBy(); 330 } 331 332 if (!sUsedBy.isEmpty()) 333 { 334 const sal_Int32 nMaxLen = 80; 335 if (sUsedBy.getLength() > nMaxLen) 336 { 337 sUsedBy = sUsedBy.copy(0, nMaxLen) + "..."; 338 } 339 340 OUString aMessage = SfxResId(STR_STYLEUSEDBY); 341 aMessage = aMessage.replaceFirst("%STYLELIST", sUsedBy); 342 sQuickHelpText = aTemplName + " " + aMessage; 343 } 344 } 345 346 Size aSize(GetOutputSizePixel().Width(), GetEntryHeight()); 347 tools::Rectangle aScreenRect(OutputToScreenPixel(GetEntryPosition(pEntry)), aSize); 348 349 Help::ShowQuickHelp(this, aScreenRect, 350 sQuickHelpText, QuickHelpFlags::Left | QuickHelpFlags::VCenter); 351 return; 352 } 353 } 354 SvTreeListBox::RequestHelp(rHEvt); 355 } 356 357 /** ListBox class that starts a PopupMenu (designer specific) in the 358 command handler. 359 */ 360 SfxActionListBox::SfxActionListBox(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinBits) 361 : DropListBox_Impl(pParent->GetWindow(), nWinBits, pParent) 362 { 363 EnableContextMenuHandling(); 364 } 365 366 void SfxActionListBox::Recalc() 367 { 368 if (officecfg::Office::Common::StylesAndFormatting::Preview::get()) 369 SetEntryHeight(32 * GetDPIScaleFactor()); 370 else 371 SetEntryHeight(STD_ENTRY_HEIGHT, true); 372 RecalcViewData(); 373 } 374 375 VclPtr<PopupMenu> SfxActionListBox::CreateContextMenu() 376 { 377 378 if( GetSelectionCount() <= 0 ) 379 { 380 pDialog->EnableEdit( false ); 381 pDialog->EnableDel( false ); 382 } 383 return pDialog->CreateContextMenu(); 384 } 385 386 SfxTemplatePanelControl::SfxTemplatePanelControl(SfxBindings* pBindings, vcl::Window* pParentWindow) 387 : Window(pParentWindow, WB_DIALOGCONTROL) 388 , pImpl(new SfxTemplateDialog_Impl(pBindings, this)) 389 , mpBindings(pBindings) 390 { 391 OSL_ASSERT(mpBindings!=nullptr); 392 393 SetStyle(GetStyle() & ~WB_DOCKABLE); 394 } 395 396 SfxTemplatePanelControl::~SfxTemplatePanelControl() 397 { 398 disposeOnce(); 399 } 400 401 void SfxTemplatePanelControl::dispose() 402 { 403 pImpl.reset(); 404 Window::dispose(); 405 } 406 407 void SfxTemplatePanelControl::Resize() 408 { 409 if(pImpl) 410 pImpl->Resize(); 411 Window::Resize(); 412 } 413 414 void SfxTemplatePanelControl::StateChanged( StateChangedType nStateChange ) 415 { 416 if (nStateChange == StateChangedType::InitShow) 417 { 418 SfxViewFrame* pFrame = mpBindings->GetDispatcher_Impl()->GetFrame(); 419 vcl::Window* pEditWin = pFrame->GetViewShell()->GetWindow(); 420 421 Size aSize = pEditWin->GetSizePixel(); 422 Point aPoint = pEditWin->OutputToScreenPixel( pEditWin->GetPosPixel() ); 423 aPoint = GetParent()->ScreenToOutputPixel( aPoint ); 424 Size aWinSize = GetSizePixel(); 425 aPoint.AdjustX(aSize.Width() - aWinSize.Width() - 20 ); 426 aPoint.AdjustY(aSize.Height() / 2 - aWinSize.Height() / 2 ); 427 // SetFloatingPos( aPoint ); 428 } 429 430 Window::StateChanged( nStateChange ); 431 } 432 433 void StyleTreeListBox_Impl::MakeExpanded_Impl(std::vector<OUString>& rEntries) const 434 { 435 SvTreeListEntry* pEntry; 436 for (pEntry = FirstVisible(); pEntry; pEntry = NextVisible(pEntry)) 437 { 438 if (IsExpanded(pEntry)) 439 { 440 rEntries.push_back(GetEntryText(pEntry)); 441 } 442 } 443 } 444 445 VclPtr<PopupMenu> StyleTreeListBox_Impl::CreateContextMenu() 446 { 447 return pDialog->CreateContextMenu(); 448 } 449 450 /** DoubleClick-Handler; calls the link. 451 SV virtual method. 452 */ 453 bool StyleTreeListBox_Impl::DoubleClickHdl() 454 { 455 aDoubleClickLink.Call(nullptr); 456 return false; 457 } 458 459 bool StyleTreeListBox_Impl::EventNotify( NotifyEvent& rNEvt ) 460 { 461 // handle <RETURN> as double click 462 463 bool bRet = false; 464 if ( rNEvt.GetType() == MouseNotifyEvent::KEYINPUT ) 465 { 466 const vcl::KeyCode& rKeyCode = rNEvt.GetKeyEvent()->GetKeyCode(); 467 if ( !rKeyCode.GetModifier() && KEY_RETURN == rKeyCode.GetCode() ) 468 { 469 aDoubleClickLink.Call( nullptr ); 470 bRet = true; 471 } 472 } 473 474 if ( !bRet ) 475 bRet = DropListBox_Impl::EventNotify( rNEvt ); 476 477 return bRet; 478 } 479 480 /** NotifyMoving Handler; This leads via a link on the event to the dialog. 481 SV virtual method. 482 */ 483 TriState StyleTreeListBox_Impl::NotifyMoving(SvTreeListEntry* pTarget, 484 SvTreeListEntry* pEntry, 485 SvTreeListEntry*& rpNewParent, 486 sal_uLong& lPos) 487 { 488 if(!pTarget || !pEntry) 489 return TRISTATE_FALSE; 490 aParent = GetEntryText(pTarget); 491 aStyle = GetEntryText(pEntry); 492 const bool bRet = aDropLink.Call(*this); 493 rpNewParent = pTarget; 494 lPos=0; 495 IntlWrapper aIntlWrapper(SvtSysLocale().GetUILanguageTag()); 496 const CollatorWrapper* pCollator = aIntlWrapper.getCaseCollator(); 497 for(SvTreeListEntry *pTmpEntry=FirstChild(pTarget); 498 pTmpEntry && pCollator->compareString( 499 GetEntryText(pTmpEntry),GetEntryText(pEntry)) < 0; 500 pTmpEntry=pTmpEntry->NextSibling(),lPos++) ; 501 502 return bRet ? TRISTATE_INDET : TRISTATE_FALSE; 503 } 504 505 /** ExpandingHdl Handler; the current entry is noticed. 506 SV virtual method. 507 508 [Cross-reference] 509 <StyleTreeListBox_Impl::ExpandedHdl()> 510 */ 511 bool StyleTreeListBox_Impl::ExpandingHdl() 512 { 513 pCurEntry = GetCurEntry(); 514 return true; 515 } 516 517 /** ExpandedHdl Handler; 518 SV virtual method. 519 520 [Cross-reference] 521 <StyleTreeListBox_Impl::ExpandingHdl()> 522 */ 523 void StyleTreeListBox_Impl::ExpandedHdl() 524 { 525 SvTreeListEntry *pEntry = GetHdlEntry(); 526 if(!IsExpanded(pEntry) && pCurEntry != GetCurEntry()) 527 SelectAll( false ); 528 pCurEntry = nullptr; 529 } 530 531 /** Constructor StyleTreeListBox_Impl */ 532 StyleTreeListBox_Impl::StyleTreeListBox_Impl(SfxCommonTemplateDialog_Impl* pParent, WinBits nWinStyle) 533 : DropListBox_Impl(pParent->GetWindow(), nWinStyle, pParent) 534 , pCurEntry(nullptr) 535 { 536 EnableContextMenuHandling(); 537 } 538 539 void StyleTreeListBox_Impl::Recalc() 540 { 541 if (officecfg::Office::Common::StylesAndFormatting::Preview::get()) 542 SetEntryHeight(32 * GetDPIScaleFactor()); 543 else 544 SetEntryHeight(STD_ENTRY_HEIGHT, true); 545 RecalcViewData(); 546 } 547 548 /** Internal structure for the establishment of the hierarchical view */ 549 namespace { 550 551 class StyleTree_Impl; 552 553 } 554 555 typedef std::vector<std::unique_ptr<StyleTree_Impl>> StyleTreeArr_Impl; 556 557 namespace { 558 559 class StyleTree_Impl 560 { 561 private: 562 OUString const aName; 563 OUString const aParent; 564 StyleTreeArr_Impl pChildren; 565 566 public: 567 bool HasParent() const { return !aParent.isEmpty(); } 568 569 StyleTree_Impl(const OUString &rName, const OUString &rParent): 570 aName(rName), aParent(rParent), pChildren(0) {} 571 572 const OUString& getName() const { return aName; } 573 const OUString& getParent() const { return aParent; } 574 StyleTreeArr_Impl& getChildren() { return pChildren; } 575 }; 576 577 } 578 579 static void MakeTree_Impl(StyleTreeArr_Impl& rArr) 580 { 581 const comphelper::string::NaturalStringSorter aSorter( 582 ::comphelper::getProcessComponentContext(), 583 Application::GetSettings().GetLanguageTag().getLocale()); 584 585 std::unordered_map<OUString, StyleTree_Impl*> styleFinder; 586 styleFinder.reserve(rArr.size()); 587 for (const auto& pEntry : rArr) 588 { 589 styleFinder.emplace(pEntry->getName(), pEntry.get()); 590 } 591 592 // Arrange all under their Parents 593 for (auto& pEntry : rArr) 594 { 595 if (!pEntry->HasParent()) 596 continue; 597 auto it = styleFinder.find(pEntry->getParent()); 598 if (it != styleFinder.end()) 599 { 600 StyleTree_Impl* pCmp = it->second; 601 // Insert child entries sorted 602 auto iPos = std::lower_bound(pCmp->getChildren().begin(), pCmp->getChildren().end(), pEntry, 603 [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; }); 604 pCmp->getChildren().insert(iPos, std::move(pEntry)); 605 } 606 } 607 608 // Only keep tree roots in rArr, child elements can be accessed through the hierarchy 609 rArr.erase(std::remove_if(rArr.begin(), rArr.end(), [](std::unique_ptr<StyleTree_Impl> const & pEntry) { return !pEntry; }), rArr.end()); 610 611 // tdf#91106 sort top level styles 612 std::sort(rArr.begin(), rArr.end(), 613 [&aSorter](std::unique_ptr<StyleTree_Impl> const & pEntry1, std::unique_ptr<StyleTree_Impl> const & pEntry2) { 614 if (pEntry2->getName() == "Default Style") 615 return false; 616 if (pEntry1->getName() == "Default Style") 617 return true; // default always first 618 return aSorter.compare(pEntry1->getName(), pEntry2->getName()) < 0; 619 }); 620 } 621 622 static bool IsExpanded_Impl( const std::vector<OUString>& rEntries, 623 const OUString &rStr) 624 { 625 for (const auto & rEntry : rEntries) 626 { 627 if (rEntry == rStr) 628 return true; 629 } 630 return false; 631 } 632 633 static SvTreeListEntry* FillBox_Impl(SvTreeListBox* pBox, 634 StyleTree_Impl* pEntry, 635 const std::vector<OUString>& rEntries, 636 SfxStyleFamily eStyleFamily, 637 SvTreeListEntry* pParent) 638 { 639 SvTreeListEntry* pTreeListEntry = pBox->InsertEntry(pEntry->getName(), pParent); 640 641 if (officecfg::Office::Common::StylesAndFormatting::Preview::get()) 642 { 643 pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(pEntry->getName(), eStyleFamily), 1); 644 } 645 646 pBox->GetModel()->InvalidateEntry(pTreeListEntry); 647 648 for(size_t i = 0; i < pEntry->getChildren().size(); ++i) 649 { 650 FillBox_Impl(pBox, pEntry->getChildren()[i].get(), rEntries, eStyleFamily, pTreeListEntry); 651 } 652 return pTreeListEntry; 653 } 654 655 656 namespace SfxTemplate 657 { 658 // converts from SFX_STYLE_FAMILY Ids to 1-6 659 static sal_uInt16 SfxFamilyIdToNId(SfxStyleFamily nFamily) 660 { 661 switch ( nFamily ) 662 { 663 case SfxStyleFamily::Char: return 1; 664 case SfxStyleFamily::Para: return 2; 665 case SfxStyleFamily::Frame: return 3; 666 case SfxStyleFamily::Page: return 4; 667 case SfxStyleFamily::Pseudo: return 5; 668 case SfxStyleFamily::Table: return 6; 669 default: return 0xffff; 670 } 671 } 672 673 // converts from 1-6 to SFX_STYLE_FAMILY Ids 674 static SfxStyleFamily NIdToSfxFamilyId(sal_uInt16 nId) 675 { 676 switch (nId) 677 { 678 case 1: return SfxStyleFamily::Char; 679 case 2: return SfxStyleFamily::Para; 680 case 3: return SfxStyleFamily::Frame; 681 case 4: return SfxStyleFamily::Page; 682 case 5: return SfxStyleFamily::Pseudo; 683 case 6: return SfxStyleFamily::Table; 684 default: return SfxStyleFamily::All; 685 } 686 } 687 } 688 689 // Constructor 690 691 SfxCommonTemplateDialog_Impl::SfxCommonTemplateDialog_Impl( SfxBindings* pB, vcl::Window* pW ) 692 : pBindings(pB) 693 , pWindow(pW) 694 , pModule(nullptr) 695 , pStyleSheetPool(nullptr) 696 , pCurObjShell(nullptr) 697 , xModuleManager(frame::ModuleManager::create(::comphelper::getProcessComponentContext())) 698 , m_pDeletionWatcher(nullptr) 699 700 , aFmtLb( VclPtr<SfxActionListBox>::Create(this, WB_BORDER | WB_TABSTOP | WB_SORT) ) 701 , pTreeBox( VclPtr<StyleTreeListBox_Impl>::Create(this, WB_HASBUTTONS | WB_HASLINES | 702 WB_BORDER | WB_TABSTOP | WB_HASLINESATROOT | 703 WB_HASBUTTONSATROOT | WB_HIDESELECTION) ) 704 , aPreviewCheckbox( VclPtr<CheckBox>::Create( pW, WB_VCENTER )) 705 , aFilterLb( VclPtr<ListBox>::Create(pW, WB_BORDER | WB_DROPDOWN | WB_TABSTOP) ) 706 707 , nActFamily(0xffff) 708 , nActFilter(0) 709 , nAppFilter(SfxStyleSearchBits::Auto) 710 711 , bDontUpdate(false) 712 , bIsWater(false) 713 , bUpdate(false) 714 , bUpdateFamily(false) 715 , bCanEdit(false) 716 , bCanDel(false) 717 , bCanNew(true) 718 , bCanHide(true) 719 , bCanShow(false) 720 , bWaterDisabled(false) 721 , bNewByExampleDisabled(false) 722 , bUpdateByExampleDisabled(false) 723 , bTreeDrag(true) 724 , bHierarchical(false) 725 , m_bWantHierarchical(false) 726 , bBindingUpdate(true) 727 { 728 aFmtLb->SetQuickSearch(true); 729 aFmtLb->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST)); 730 aFmtLb->SetHelpId( HID_TEMPLATE_FMT ); 731 aFilterLb->SetHelpId( HID_TEMPLATE_FILTER ); 732 aFmtLb->SetStyle( aFmtLb->GetStyle() | WB_SORT | WB_HIDESELECTION ); 733 vcl::Font aFont = aFmtLb->GetFont(); 734 aFont.SetWeight( WEIGHT_NORMAL ); 735 aFmtLb->SetFont( aFont ); 736 pTreeBox->SetQuickSearch(true); 737 pTreeBox->SetNodeDefaultImages(); 738 pTreeBox->SetOptimalImageIndent(); 739 pTreeBox->SetAccessibleName(SfxResId(STR_STYLE_ELEMTLIST)); 740 aPreviewCheckbox->Check(officecfg::Office::Common::StylesAndFormatting::Preview::get()); 741 aPreviewCheckbox->SetText( SfxResId(STR_PREVIEW_CHECKBOX) ); 742 } 743 744 sal_uInt16 SfxCommonTemplateDialog_Impl::StyleNrToInfoOffset(sal_uInt16 nId) 745 { 746 const SfxStyleFamilyItem& rItem = pStyleFamilies->at( nId ); 747 return SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily())-1; 748 } 749 750 void SfxTemplateDialog_Impl::EnableEdit(bool bEnable) 751 { 752 SfxCommonTemplateDialog_Impl::EnableEdit( bEnable ); 753 if( !bEnable || !bUpdateByExampleDisabled ) 754 EnableItem( SID_STYLE_UPDATE_BY_EXAMPLE, bEnable); 755 } 756 757 void SfxCommonTemplateDialog_Impl::ReadResource() 758 { 759 // Read global user resource 760 for (auto & i : pFamilyState) 761 i.reset(); 762 763 SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame(); 764 pCurObjShell = pViewFrame->GetObjectShell(); 765 pModule = pCurObjShell ? pCurObjShell->GetModule() : nullptr; 766 if (pModule) 767 pStyleFamilies = pModule->CreateStyleFamilies(); 768 if (!pStyleFamilies) 769 pStyleFamilies.reset(new SfxStyleFamilies); 770 771 nActFilter = 0xffff; 772 if (pCurObjShell) 773 { 774 nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pCurObjShell ) ); 775 if ( 0xffff == nActFilter ) 776 nActFilter = pCurObjShell->GetAutoStyleFilterIndex(); 777 } 778 779 // Paste in the toolbox 780 // reverse order, since always inserted at the head 781 size_t nCount = pStyleFamilies->size(); 782 783 pBindings->ENTERREGISTRATIONS(); 784 785 size_t i; 786 for (i = 0; i < nCount; ++i) 787 { 788 sal_uInt16 nSlot = 0; 789 switch (pStyleFamilies->at(i).GetFamily()) 790 { 791 case SfxStyleFamily::Char: 792 nSlot = SID_STYLE_FAMILY1; break; 793 case SfxStyleFamily::Para: 794 nSlot = SID_STYLE_FAMILY2; break; 795 case SfxStyleFamily::Frame: 796 nSlot = SID_STYLE_FAMILY3; break; 797 case SfxStyleFamily::Page: 798 nSlot = SID_STYLE_FAMILY4; break; 799 case SfxStyleFamily::Pseudo: 800 nSlot = SID_STYLE_FAMILY5; break; 801 case SfxStyleFamily::Table: 802 nSlot = SID_STYLE_FAMILY6; break; 803 default: OSL_FAIL("unknown StyleFamily"); break; 804 } 805 pBoundItems[i].reset( 806 new SfxTemplateControllerItem(nSlot, *this, *pBindings) ); 807 } 808 pBoundItems[i++].reset( new SfxTemplateControllerItem( 809 SID_STYLE_WATERCAN, *this, *pBindings) ); 810 pBoundItems[i++].reset( new SfxTemplateControllerItem( 811 SID_STYLE_NEW_BY_EXAMPLE, *this, *pBindings) ); 812 pBoundItems[i++].reset( new SfxTemplateControllerItem( 813 SID_STYLE_UPDATE_BY_EXAMPLE, *this, *pBindings) ); 814 pBoundItems[i++].reset( new SfxTemplateControllerItem( 815 SID_STYLE_NEW, *this, *pBindings) ); 816 pBoundItems[i++].reset( new SfxTemplateControllerItem( 817 SID_STYLE_DRAGHIERARCHIE, *this, *pBindings) ); 818 pBoundItems[i++].reset( new SfxTemplateControllerItem( 819 SID_STYLE_EDIT, *this, *pBindings) ); 820 pBoundItems[i++].reset( new SfxTemplateControllerItem( 821 SID_STYLE_DELETE, *this, *pBindings) ); 822 pBoundItems[i++].reset( new SfxTemplateControllerItem( 823 SID_STYLE_FAMILY, *this, *pBindings) ); 824 pBindings->LEAVEREGISTRATIONS(); 825 826 for(; i < COUNT_BOUND_FUNC; ++i) 827 pBoundItems[i] = nullptr; 828 829 StartListening(*pBindings); 830 831 // Insert in the reverse order of occurrence in the Style Families. This is for 832 // the toolbar of the designer. The list box of the catalog respects the 833 // correct order by itself. 834 835 // Sequences: the order of Resource = the order of Toolbar for example list box. 836 // Order of ascending SIDs: Low SIDs are displayed first when templates of 837 // several families are active. 838 839 // in the Writer the UpdateStyleByExample Toolbox button is removed and 840 // the NewStyle button gets a PopupMenu 841 if(nCount > 4) 842 ReplaceUpdateButtonByMenu(); 843 844 for( ; nCount--; ) 845 { 846 const SfxStyleFamilyItem &rItem = pStyleFamilies->at( nCount ); 847 sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId( rItem.GetFamily() ); 848 InsertFamilyItem(nId, rItem); 849 } 850 851 LoadedFamilies(); 852 853 for ( i = SID_STYLE_FAMILY1; i <= SID_STYLE_FAMILY4; i++ ) 854 pBindings->Update(i); 855 } 856 857 void SfxCommonTemplateDialog_Impl::ClearResource() 858 { 859 ClearFamilyList(); 860 impl_clear(); 861 } 862 863 void SfxCommonTemplateDialog_Impl::impl_clear() 864 { 865 pStyleFamilies.reset(); 866 for (auto & i : pFamilyState) 867 i.reset(); 868 for (auto & i : pBoundItems) 869 i.reset(); 870 pCurObjShell = nullptr; 871 } 872 873 SfxCommonTemplateDialog_Impl::DeletionWatcher * 874 SfxCommonTemplateDialog_Impl::impl_setDeletionWatcher( 875 DeletionWatcher *const pNewWatcher) 876 { 877 DeletionWatcher *const pRet(m_pDeletionWatcher); 878 m_pDeletionWatcher = pNewWatcher; 879 return pRet; 880 } 881 882 void SfxCommonTemplateDialog_Impl::Initialize() 883 { 884 // Read global user resource 885 ReadResource(); 886 pBindings->Invalidate( SID_STYLE_FAMILY ); 887 pBindings->Update( SID_STYLE_FAMILY ); 888 889 Update_Impl(); 890 891 aFilterLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FilterSelectHdl ) ); 892 aFmtLb->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl, TreeListApplyHdl ) ); 893 aFmtLb->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) ); 894 aFmtLb->SetSelectionMode(SelectionMode::Multiple); 895 pTreeBox->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, FmtSelectHdl ) ); 896 pTreeBox->SetDoubleClickHdl( LINK( this, SfxCommonTemplateDialog_Impl, ApplyHdl ) ); 897 pTreeBox->SetDropHdl( LINK( this, SfxCommonTemplateDialog_Impl, DropHdl ) ); 898 aPreviewCheckbox->SetClickHdl( LINK(this, SfxCommonTemplateDialog_Impl, PreviewHdl)); 899 900 901 aFilterLb->Show(); 902 if (!bHierarchical) 903 aFmtLb->Show(); 904 aPreviewCheckbox->Show(); 905 } 906 907 SfxCommonTemplateDialog_Impl::~SfxCommonTemplateDialog_Impl() 908 { 909 #if defined STYLESPREVIEW 910 Execute_Impl(SID_STYLE_END_PREVIEW, 911 OUString(), OUString(), 912 0, 0, 0, 0 ); 913 #endif 914 if ( bIsWater ) 915 Execute_Impl(SID_STYLE_WATERCAN, "", "", 0); 916 GetWindow()->Hide(); 917 impl_clear(); 918 if ( pStyleSheetPool ) 919 EndListening(*pStyleSheetPool); 920 pStyleSheetPool = nullptr; 921 pTreeBox.disposeAndClear(); 922 pIdle.reset(); 923 if ( m_pDeletionWatcher ) 924 m_pDeletionWatcher->signal(); 925 aFmtLb.disposeAndClear(); 926 aPreviewCheckbox.disposeAndClear(); 927 aFilterLb.disposeAndClear(); 928 } 929 930 // Helper function: Access to the current family item 931 const SfxStyleFamilyItem *SfxCommonTemplateDialog_Impl::GetFamilyItem_Impl() const 932 { 933 const size_t nCount = pStyleFamilies->size(); 934 for(size_t i = 0; i < nCount; ++i) 935 { 936 const SfxStyleFamilyItem &rItem = pStyleFamilies->at( i ); 937 sal_uInt16 nId = SfxTemplate::SfxFamilyIdToNId(rItem.GetFamily()); 938 if(nId == nActFamily) 939 return &rItem; 940 } 941 return nullptr; 942 } 943 944 void SfxCommonTemplateDialog_Impl::GetSelectedStyle() const 945 { 946 if (!IsInitialized() || !pStyleSheetPool || !HasSelectedStyle()) 947 return; 948 const OUString aTemplName( GetSelectedEntry() ); 949 const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); 950 pStyleSheetPool->Find( aTemplName, pItem->GetFamily() ); 951 } 952 953 /** 954 * Is it safe to show the water-can / fill icon. If we've a 955 * hierarchical widget - we have only single select, otherwise 956 * we need to check if we have a multi-selection. We either have 957 * a pTreeBox showing or an aFmtLb (which we hide when not shown) 958 */ 959 bool SfxCommonTemplateDialog_Impl::IsSafeForWaterCan() const 960 { 961 if ( pTreeBox->IsVisible() ) 962 return pTreeBox->FirstSelected() != nullptr; 963 else 964 return aFmtLb->GetSelectionCount() == 1; 965 } 966 967 void SfxCommonTemplateDialog_Impl::SelectStyle(const OUString &rStr) 968 { 969 const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); 970 if ( !pItem ) 971 return; 972 const SfxStyleFamily eFam = pItem->GetFamily(); 973 SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( rStr, eFam ); 974 if( pStyle ) 975 { 976 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly); 977 EnableEdit( bReadWrite ); 978 EnableHide( bReadWrite && !pStyle->IsHidden( ) && !pStyle->IsUsed( ) ); 979 EnableShow( bReadWrite && pStyle->IsHidden( ) ); 980 } 981 else 982 { 983 EnableEdit( false ); 984 EnableHide( false ); 985 EnableShow( false ); 986 } 987 988 if ( pTreeBox->IsVisible() ) 989 { 990 if ( !rStr.isEmpty() ) 991 { 992 SvTreeListEntry* pEntry = pTreeBox->First(); 993 while ( pEntry ) 994 { 995 if ( pTreeBox->GetEntryText( pEntry ) == rStr ) 996 { 997 pTreeBox->MakeVisible( pEntry ); 998 pTreeBox->Select( pEntry ); 999 return; 1000 } 1001 pEntry = pTreeBox->Next( pEntry ); 1002 } 1003 } 1004 else 1005 pTreeBox->SelectAll( false ); 1006 } 1007 else 1008 { 1009 bool bSelect = ! rStr.isEmpty(); 1010 if ( bSelect ) 1011 { 1012 SvTreeListEntry* pEntry = aFmtLb->FirstVisible(); 1013 while ( pEntry && aFmtLb->GetEntryText( pEntry ) != rStr ) 1014 pEntry = aFmtLb->NextVisible( pEntry ); 1015 if ( !pEntry ) 1016 bSelect = false; 1017 else 1018 { 1019 if (!aFmtLb->IsSelected(pEntry)) 1020 { 1021 aFmtLb->MakeVisible( pEntry ); 1022 aFmtLb->SelectAll(false); 1023 aFmtLb->Select( pEntry ); 1024 bWaterDisabled = !IsSafeForWaterCan(); 1025 FmtSelectHdl( nullptr ); 1026 } 1027 } 1028 } 1029 1030 if ( !bSelect ) 1031 { 1032 aFmtLb->SelectAll( false ); 1033 EnableEdit(false); 1034 EnableHide( false ); 1035 EnableShow( false ); 1036 } 1037 } 1038 } 1039 1040 OUString SfxCommonTemplateDialog_Impl::GetSelectedEntry() const 1041 { 1042 OUString aRet; 1043 if ( pTreeBox->IsVisible() ) 1044 { 1045 SvTreeListEntry* pEntry = pTreeBox->FirstSelected(); 1046 if ( pEntry ) 1047 aRet = pTreeBox->GetEntryText( pEntry ); 1048 } 1049 else 1050 { 1051 SvTreeListEntry* pEntry = aFmtLb->FirstSelected(); 1052 if ( pEntry ) 1053 aRet = aFmtLb->GetEntryText( pEntry ); 1054 } 1055 return aRet; 1056 } 1057 1058 void SfxCommonTemplateDialog_Impl::EnableTreeDrag( bool bEnable ) 1059 { 1060 if ( pStyleSheetPool ) 1061 { 1062 SfxStyleSheetBase* pStyle = pStyleSheetPool->First(); 1063 if ( pTreeBox->IsVisible() ) 1064 { 1065 if ( pStyle && pStyle->HasParentSupport() && bEnable ) 1066 pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE); 1067 else 1068 pTreeBox->SetDragDropMode(DragDropMode::NONE); 1069 } 1070 } 1071 bTreeDrag = bEnable; 1072 } 1073 1074 void SfxCommonTemplateDialog_Impl::FillTreeBox() 1075 { 1076 OSL_ENSURE( pTreeBox, "FillTreeBox() without treebox"); 1077 if (!pStyleSheetPool || nActFamily == 0xffff) 1078 return; 1079 1080 const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); 1081 if (!pItem) 1082 return; 1083 pStyleSheetPool->SetSearchMask(pItem->GetFamily(), SfxStyleSearchBits::AllVisible); 1084 StyleTreeArr_Impl aArr; 1085 SfxStyleSheetBase* pStyle = pStyleSheetPool->First(); 1086 1087 if(pStyle && pStyle->HasParentSupport() && bTreeDrag ) 1088 pTreeBox->SetDragDropMode(DragDropMode::CTRL_MOVE); 1089 else 1090 pTreeBox->SetDragDropMode(DragDropMode::NONE); 1091 1092 while (pStyle) 1093 { 1094 StyleTree_Impl* pNew = new StyleTree_Impl(pStyle->GetName(), pStyle->GetParent()); 1095 aArr.emplace_back(pNew); 1096 pStyle = pStyleSheetPool->Next(); 1097 } 1098 1099 MakeTree_Impl(aArr); 1100 std::vector<OUString> aEntries; 1101 pTreeBox->MakeExpanded_Impl(aEntries); 1102 pTreeBox->SetUpdateMode( false ); 1103 pTreeBox->Clear(); 1104 const sal_uInt16 nCount = aArr.size(); 1105 1106 for (sal_uInt16 i = 0; i < nCount; ++i) 1107 { 1108 FillBox_Impl(pTreeBox, aArr[i].get(), aEntries, pItem->GetFamily(), nullptr); 1109 aArr[i].reset(); 1110 } 1111 pTreeBox->Recalc(); 1112 1113 EnableItem(SID_STYLE_WATERCAN, false); 1114 1115 SfxTemplateItem* pState = pFamilyState[nActFamily - 1].get(); 1116 1117 if (nCount) 1118 pTreeBox->Expand(pTreeBox->First()); 1119 1120 for (SvTreeListEntry* pEntry = pTreeBox->First(); pEntry; pEntry = pTreeBox->Next(pEntry)) 1121 { 1122 if (IsExpanded_Impl(aEntries, pTreeBox->GetEntryText(pEntry))) 1123 pTreeBox->Expand(pEntry); 1124 } 1125 1126 pTreeBox->SetUpdateMode( true ); 1127 1128 OUString aStyle; 1129 if(pState) // Select current entry 1130 aStyle = pState->GetStyleName(); 1131 SelectStyle(aStyle); 1132 EnableDelete(); 1133 } 1134 1135 bool SfxCommonTemplateDialog_Impl::HasSelectedStyle() const 1136 { 1137 return pTreeBox->IsVisible()? pTreeBox->FirstSelected() != nullptr: 1138 aFmtLb->GetSelectionCount() != 0; 1139 } 1140 1141 // internal: Refresh the display 1142 // nFlags: what we should update. 1143 void SfxCommonTemplateDialog_Impl::UpdateStyles_Impl(StyleFlags nFlags) 1144 { 1145 OSL_ENSURE(nFlags != StyleFlags::NONE, "nothing to do"); 1146 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 1147 if (!pItem) 1148 { 1149 // Is the case for the template catalog 1150 const size_t nFamilyCount = pStyleFamilies->size(); 1151 size_t n; 1152 for( n = 0; n < nFamilyCount; n++ ) 1153 if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break; 1154 if ( n == nFamilyCount ) 1155 // It happens sometimes, God knows why 1156 return; 1157 nAppFilter = pFamilyState[StyleNrToInfoOffset(n)]->GetValue(); 1158 FamilySelect( StyleNrToInfoOffset(n)+1 ); 1159 pItem = GetFamilyItem_Impl(); 1160 } 1161 1162 const SfxStyleFamily eFam = pItem->GetFamily(); 1163 1164 SfxStyleSearchBits nFilter (nActFilter < pItem->GetFilterList().size() ? pItem->GetFilterList()[nActFilter].nFlags : SfxStyleSearchBits::Auto); 1165 if(nFilter == SfxStyleSearchBits::Auto) // automatic 1166 nFilter = nAppFilter; 1167 1168 OSL_ENSURE(pStyleSheetPool, "no StyleSheetPool"); 1169 if(!pStyleSheetPool) 1170 return; 1171 1172 pStyleSheetPool->SetSearchMask(eFam, nFilter); 1173 pItem = GetFamilyItem_Impl(); 1174 if(nFlags & StyleFlags::UpdateFamily) // Update view type list (Hierarchical, All, etc. 1175 { 1176 CheckItem(nActFamily); // check Button in Toolbox 1177 aFilterLb->SetUpdateMode(false); 1178 aFilterLb->Clear(); 1179 //insert hierarchical at the beginning 1180 sal_Int32 nPos = aFilterLb->InsertEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL), 0); 1181 aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(SfxStyleSearchBits::All) ); 1182 const SfxStyleFilter& rFilter = pItem->GetFilterList(); 1183 for(const SfxFilterTuple& i : rFilter) 1184 { 1185 SfxStyleSearchBits nFilterFlags = i.nFlags; 1186 nPos = aFilterLb->InsertEntry( i.aName ); 1187 aFilterLb->SetEntryData( nPos, reinterpret_cast<void*>(nFilterFlags) ); 1188 } 1189 if(nActFilter < aFilterLb->GetEntryCount() - 1) 1190 aFilterLb->SelectEntryPos(nActFilter + 1); 1191 else 1192 { 1193 nActFilter = 0; 1194 aFilterLb->SelectEntryPos(1); 1195 SfxStyleSearchBits nFilterFlags = (nActFilter < rFilter.size()) ? rFilter[nActFilter].nFlags : SfxStyleSearchBits::Auto; 1196 pStyleSheetPool->SetSearchMask(eFam, nFilterFlags); 1197 } 1198 1199 // if the tree view again, select family hierarchy 1200 if (pTreeBox->IsVisible() || m_bWantHierarchical) 1201 { 1202 aFilterLb->SelectEntry(SfxResId(STR_STYLE_FILTER_HIERARCHICAL)); 1203 EnableHierarchical(true); 1204 } 1205 1206 // show maximum 14 entries 1207 aFilterLb->SetDropDownLineCount( MAX_FILTER_ENTRIES ); 1208 aFilterLb->SetUpdateMode(true); 1209 } 1210 else 1211 { 1212 if (nActFilter < aFilterLb->GetEntryCount() - 1) 1213 aFilterLb->SelectEntryPos(nActFilter + 1); 1214 else 1215 { 1216 nActFilter = 0; 1217 aFilterLb->SelectEntryPos(1); 1218 } 1219 } 1220 1221 if(!(nFlags & StyleFlags::UpdateFamilyList)) 1222 return; 1223 1224 EnableItem(SID_STYLE_WATERCAN,false); 1225 1226 SfxStyleSheetBase *pStyle = pStyleSheetPool->First(); 1227 SvTreeListEntry* pEntry = aFmtLb->First(); 1228 std::vector<OUString> aStrings; 1229 1230 comphelper::string::NaturalStringSorter aSorter( 1231 ::comphelper::getProcessComponentContext(), 1232 Application::GetSettings().GetLanguageTag().getLocale()); 1233 1234 while( pStyle ) 1235 { 1236 aStrings.push_back(pStyle->GetName()); 1237 pStyle = pStyleSheetPool->Next(); 1238 } 1239 1240 // Paradoxically, with a list and non-Latin style names, 1241 // sorting twice is faster than sorting once. 1242 // The first sort has a cheap comparator, and gets the list into mostly-sorted order. 1243 // Then the second sort needs to call its (much more expensive) comparator less often. 1244 std::sort(aStrings.begin(), aStrings.end()); 1245 std::sort(aStrings.begin(), aStrings.end(), 1246 [&aSorter](const OUString& rLHS, const OUString& rRHS) { 1247 return aSorter.compare(rLHS, rRHS) < 0; 1248 }); 1249 1250 size_t nCount = aStrings.size(); 1251 size_t nPos = 0; 1252 while(nPos < nCount && pEntry && 1253 aStrings[nPos] == aFmtLb->GetEntryText(pEntry)) 1254 { 1255 ++nPos; 1256 pEntry = aFmtLb->Next( pEntry ); 1257 } 1258 1259 if( nPos < nCount || pEntry ) 1260 { 1261 // Fills the display box 1262 aFmtLb->SetUpdateMode(false); 1263 aFmtLb->Clear(); 1264 1265 for(nPos = 0; nPos < nCount; ++nPos) 1266 { 1267 SvTreeListEntry* pTreeListEntry = aFmtLb->InsertEntry(aStrings[nPos], nullptr, false, nPos); 1268 if (officecfg::Office::Common::StylesAndFormatting::Preview::get()) 1269 { 1270 pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(aStrings[nPos], eFam), 1); 1271 } 1272 aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry); 1273 } 1274 aFmtLb->Recalc(); 1275 aFmtLb->SetUpdateMode(true); 1276 } 1277 // Selects the current style if any 1278 SfxTemplateItem *pState = pFamilyState[nActFamily-1].get(); 1279 OUString aStyle; 1280 if(pState) 1281 aStyle = pState->GetStyleName(); 1282 #if defined STYLESPREVIEW 1283 mbIgnoreSelect = true; // in case we get a selection change 1284 // in any case we should stop any preview 1285 Execute_Impl(SID_STYLE_END_PREVIEW, 1286 OUString(), OUString(), 1287 0, 0, 0, 0 ); 1288 #endif 1289 SelectStyle(aStyle); 1290 EnableDelete(); 1291 } 1292 1293 // Updated display: Watering the house 1294 void SfxCommonTemplateDialog_Impl::SetWaterCanState(const SfxBoolItem *pItem) 1295 { 1296 bWaterDisabled = (pItem == nullptr); 1297 1298 if(!bWaterDisabled) 1299 //make sure the watercan is only activated when there is (only) one selection 1300 bWaterDisabled = !IsSafeForWaterCan(); 1301 1302 if(pItem && !bWaterDisabled) 1303 { 1304 CheckItem(SID_STYLE_WATERCAN, pItem->GetValue()); 1305 EnableItem( SID_STYLE_WATERCAN ); 1306 } 1307 else 1308 { 1309 if(!bWaterDisabled) 1310 EnableItem(SID_STYLE_WATERCAN); 1311 else 1312 EnableItem(SID_STYLE_WATERCAN, false); 1313 } 1314 1315 // Ignore while in watercan mode statusupdates 1316 1317 size_t nCount = pStyleFamilies->size(); 1318 pBindings->EnterRegistrations(); 1319 for(size_t n = 0; n < nCount; n++) 1320 { 1321 SfxControllerItem *pCItem=pBoundItems[n].get(); 1322 bool bChecked = pItem && pItem->GetValue(); 1323 if( pCItem->IsBound() == bChecked ) 1324 { 1325 if( !bChecked ) 1326 pCItem->ReBind(); 1327 else 1328 pCItem->UnBind(); 1329 } 1330 } 1331 pBindings->LeaveRegistrations(); 1332 } 1333 1334 // Item with the status of a Family is copied and noted 1335 // (is updated when all states have also been updated.) 1336 // See also: <SfxBindings::AddDoneHdl(const Link &)> 1337 void SfxCommonTemplateDialog_Impl::SetFamilyState( sal_uInt16 nSlotId, const SfxTemplateItem* pItem ) 1338 { 1339 sal_uInt16 nIdx = nSlotId - SID_STYLE_FAMILY_START; 1340 pFamilyState[nIdx].reset(); 1341 if ( pItem ) 1342 pFamilyState[nIdx].reset( new SfxTemplateItem(*pItem) ); 1343 bUpdate = true; 1344 1345 // If used templates (how the hell you find this out??) 1346 bUpdateFamily = true; 1347 } 1348 1349 // Notice from SfxBindings that the update is completed. Pushes out the update 1350 // of the display. 1351 void SfxCommonTemplateDialog_Impl::Update_Impl() 1352 { 1353 bool bDocChanged=false; 1354 SfxStyleSheetBasePool* pNewPool = nullptr; 1355 SfxViewFrame* pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame(); 1356 SfxObjectShell* pDocShell = pViewFrame->GetObjectShell(); 1357 if( pDocShell ) 1358 pNewPool = pDocShell->GetStyleSheetPool(); 1359 1360 if ( pNewPool != pStyleSheetPool && pDocShell ) 1361 { 1362 SfxModule* pNewModule = pDocShell->GetModule(); 1363 if( pNewModule && pNewModule != pModule ) 1364 { 1365 ClearResource(); 1366 ReadResource(); 1367 } 1368 if ( pStyleSheetPool ) 1369 { 1370 EndListening(*pStyleSheetPool); 1371 pStyleSheetPool = nullptr; 1372 } 1373 1374 if ( pNewPool ) 1375 { 1376 StartListening(*pNewPool); 1377 pStyleSheetPool = pNewPool; 1378 bDocChanged=true; 1379 } 1380 } 1381 1382 if (bUpdateFamily) 1383 UpdateFamily_Impl(); 1384 1385 sal_uInt16 i; 1386 for(i = 0; i < MAX_FAMILIES; ++i) 1387 if(pFamilyState[i]) 1388 break; 1389 if(i == MAX_FAMILIES || !pNewPool) 1390 // nothing is allowed 1391 return; 1392 1393 SfxTemplateItem *pItem = nullptr; 1394 // current region not within the allowed region or default 1395 if(nActFamily == 0xffff || nullptr == (pItem = pFamilyState[nActFamily-1].get() ) ) 1396 { 1397 CheckItem(nActFamily, false); 1398 const size_t nFamilyCount = pStyleFamilies->size(); 1399 size_t n; 1400 for( n = 0; n < nFamilyCount; n++ ) 1401 if( pFamilyState[ StyleNrToInfoOffset(n) ] ) break; 1402 1403 std::unique_ptr<SfxTemplateItem> & pNewItem = pFamilyState[StyleNrToInfoOffset(n)]; 1404 nAppFilter = pNewItem->GetValue(); 1405 FamilySelect( StyleNrToInfoOffset(n) + 1 ); 1406 pItem = pNewItem.get(); 1407 } 1408 else if( bDocChanged ) 1409 { 1410 // other DocShell -> all new 1411 CheckItem( nActFamily ); 1412 nActFilter = static_cast< sal_uInt16 >( LoadFactoryStyleFilter( pDocShell ) ); 1413 if ( 0xffff == nActFilter ) 1414 nActFilter = pDocShell->GetAutoStyleFilterIndex(); 1415 1416 nAppFilter = pItem->GetValue(); 1417 if(!pTreeBox->IsVisible()) 1418 { 1419 UpdateStyles_Impl(StyleFlags::UpdateFamilyList); 1420 } 1421 else 1422 FillTreeBox(); 1423 } 1424 else 1425 { 1426 // other filters for automatic 1427 CheckItem( nActFamily ); 1428 const SfxStyleFamilyItem *pStyleItem = GetFamilyItem_Impl(); 1429 if ( pStyleItem && SfxStyleSearchBits::Auto == pStyleItem->GetFilterList()[nActFilter].nFlags 1430 && nAppFilter != pItem->GetValue()) 1431 { 1432 nAppFilter = pItem->GetValue(); 1433 if(!pTreeBox->IsVisible()) 1434 UpdateStyles_Impl(StyleFlags::UpdateFamilyList); 1435 else 1436 FillTreeBox(); 1437 } 1438 else 1439 nAppFilter = pItem->GetValue(); 1440 } 1441 const OUString aStyle(pItem->GetStyleName()); 1442 SelectStyle(aStyle); 1443 EnableDelete(); 1444 EnableNew( bCanNew ); 1445 } 1446 1447 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TimeOut, Timer *, void ) 1448 { 1449 if(!bDontUpdate) 1450 { 1451 bDontUpdate=true; 1452 if(!pTreeBox->IsVisible()) 1453 UpdateStyles_Impl(StyleFlags::UpdateFamilyList); 1454 else 1455 { 1456 FillTreeBox(); 1457 SfxTemplateItem *pState = pFamilyState[nActFamily-1].get(); 1458 if(pState) 1459 { 1460 SelectStyle(pState->GetStyleName()); 1461 EnableDelete(); 1462 } 1463 } 1464 bDontUpdate=false; 1465 pIdle.reset(); 1466 } 1467 else 1468 pIdle->Start(); 1469 } 1470 1471 void SfxCommonTemplateDialog_Impl::Notify(SfxBroadcaster& /*rBC*/, const SfxHint& rHint) 1472 { 1473 const SfxHintId nId = rHint.GetId(); 1474 1475 // tap update 1476 switch(nId) 1477 { 1478 case SfxHintId::UpdateDone: 1479 { 1480 SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame(); 1481 SfxObjectShell *pDocShell = pViewFrame->GetObjectShell(); 1482 if ( 1483 bUpdate && 1484 ( 1485 !IsCheckedItem(SID_STYLE_WATERCAN) || 1486 (pDocShell && pDocShell->GetStyleSheetPool() != pStyleSheetPool) 1487 ) 1488 ) 1489 { 1490 bUpdate = false; 1491 Update_Impl(); 1492 } 1493 else if ( bUpdateFamily ) 1494 { 1495 UpdateFamily_Impl(); 1496 } 1497 1498 if( pStyleSheetPool ) 1499 { 1500 OUString aStr = GetSelectedEntry(); 1501 if (!aStr.isEmpty()) 1502 { 1503 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 1504 if( !pItem ) break; 1505 const SfxStyleFamily eFam = pItem->GetFamily(); 1506 SfxStyleSheetBase *pStyle = pStyleSheetPool->Find( aStr, eFam ); 1507 if( pStyle ) 1508 { 1509 bool bReadWrite = !(pStyle->GetMask() & SfxStyleSearchBits::ReadOnly); 1510 EnableEdit( bReadWrite ); 1511 EnableHide( bReadWrite && !pStyle->IsUsed( ) && !pStyle->IsHidden( ) ); 1512 EnableShow( bReadWrite && pStyle->IsHidden( ) ); 1513 } 1514 else 1515 { 1516 EnableEdit(false); 1517 EnableHide(false); 1518 EnableShow(false); 1519 } 1520 } 1521 } 1522 break; 1523 } 1524 1525 // Necessary if switching between documents and in both documents 1526 // the same template is used. Do not immediately call Update_Impl, 1527 // for the case that one of the documents is an internal InPlaceObject! 1528 case SfxHintId::DocChanged: 1529 bUpdate = true; 1530 break; 1531 case SfxHintId::Dying: 1532 { 1533 EndListening(*pStyleSheetPool); 1534 pStyleSheetPool=nullptr; 1535 break; 1536 } 1537 default: break; 1538 } 1539 1540 // Do not set timer when the stylesheet pool is in the box, because it is 1541 // possible that a new one is registered after the timer is up - 1542 // works bad in UpdateStyles_Impl ()! 1543 1544 if(!bDontUpdate && nId != SfxHintId::Dying && 1545 (dynamic_cast<const SfxStyleSheetPoolHint*>(&rHint) || 1546 dynamic_cast<const SfxStyleSheetHint*>(&rHint) || 1547 dynamic_cast<const SfxStyleSheetModifiedHint*>(&rHint) || 1548 nId == SfxHintId::StyleSheetModified)) 1549 { 1550 if(!pIdle) 1551 { 1552 pIdle.reset(new Idle("SfxCommonTemplate")); 1553 pIdle->SetPriority(TaskPriority::LOWEST); 1554 pIdle->SetInvokeHandler(LINK(this,SfxCommonTemplateDialog_Impl,TimeOut)); 1555 } 1556 pIdle->Start(); 1557 1558 } 1559 } 1560 1561 // Other filters; can be switched by the users or as a result of new or 1562 // editing, if the current document has been assigned a different filter. 1563 void SfxCommonTemplateDialog_Impl::FilterSelect( 1564 sal_uInt16 nEntry, // Idx of the new Filters 1565 bool bForce ) // Force update, even if the new filter is 1566 // equal to the current 1567 { 1568 if( nEntry == nActFilter && !bForce ) 1569 return; 1570 1571 nActFilter = nEntry; 1572 SfxObjectShell *const pDocShell = SaveSelection(); 1573 SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool; 1574 pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr; 1575 if ( pOldStyleSheetPool != pStyleSheetPool ) 1576 { 1577 if ( pOldStyleSheetPool ) 1578 EndListening(*pOldStyleSheetPool); 1579 if ( pStyleSheetPool ) 1580 StartListening(*pStyleSheetPool); 1581 } 1582 1583 UpdateStyles_Impl(StyleFlags::UpdateFamilyList); 1584 } 1585 1586 // Internal: Perform functions through the Dispatcher 1587 bool SfxCommonTemplateDialog_Impl::Execute_Impl( 1588 sal_uInt16 nId, const OUString &rStr, const OUString& rRefStr, sal_uInt16 nFamily, 1589 SfxStyleSearchBits nMask, sal_uInt16 *pIdx, const sal_uInt16* pModifier) 1590 { 1591 SfxDispatcher &rDispatcher = *SfxGetpApp()->GetDispatcher_Impl(); 1592 SfxStringItem aItem(nId, rStr); 1593 SfxUInt16Item aFamily(SID_STYLE_FAMILY, nFamily); 1594 SfxUInt16Item aMask( SID_STYLE_MASK, static_cast<sal_uInt16>(nMask) ); 1595 SfxStringItem aUpdName(SID_STYLE_UPD_BY_EX_NAME, rStr); 1596 SfxStringItem aRefName( SID_STYLE_REFERENCE, rRefStr ); 1597 const SfxPoolItem* pItems[ 6 ]; 1598 sal_uInt16 nCount = 0; 1599 if( !rStr.isEmpty() ) 1600 pItems[ nCount++ ] = &aItem; 1601 pItems[ nCount++ ] = &aFamily; 1602 if( nMask != SfxStyleSearchBits::Auto ) 1603 pItems[ nCount++ ] = &aMask; 1604 if(SID_STYLE_UPDATE_BY_EXAMPLE == nId) 1605 { 1606 // Special solution for Numbering update in Writer 1607 const OUString aTemplName(GetSelectedEntry()); 1608 aUpdName.SetValue(aTemplName); 1609 pItems[ nCount++ ] = &aUpdName; 1610 } 1611 1612 if ( !rRefStr.isEmpty() ) 1613 pItems[ nCount++ ] = &aRefName; 1614 1615 pItems[ nCount++ ] = nullptr; 1616 1617 DeletionWatcher aDeleted(*this); 1618 sal_uInt16 nModi = pModifier ? *pModifier : 0; 1619 const SfxPoolItem* pItem = rDispatcher.Execute( 1620 nId, SfxCallMode::SYNCHRON | SfxCallMode::RECORD, 1621 pItems, nModi ); 1622 1623 // Dialog can be destroyed while in Execute() because started 1624 // subdialogs are not modal to it (#i97888#). 1625 if ( !pItem || aDeleted ) 1626 return false; 1627 1628 if ( (nId == SID_STYLE_NEW || SID_STYLE_EDIT == nId) && (pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1) ) 1629 { 1630 const SfxUInt16Item *pFilterItem = dynamic_cast< const SfxUInt16Item* >(pItem); 1631 assert(pFilterItem); 1632 SfxStyleSearchBits nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()) & ~SfxStyleSearchBits::UserDefined; 1633 if(nFilterFlags == SfxStyleSearchBits::Auto) // User Template? 1634 nFilterFlags = static_cast<SfxStyleSearchBits>(pFilterItem->GetValue()); 1635 const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl(); 1636 const size_t nFilterCount = pFamilyItem->GetFilterList().size(); 1637 1638 for ( size_t i = 0; i < nFilterCount; ++i ) 1639 { 1640 const SfxFilterTuple &rTupel = pFamilyItem->GetFilterList()[ i ]; 1641 1642 if ( ( rTupel.nFlags & nFilterFlags ) == nFilterFlags && pIdx ) 1643 *pIdx = i; 1644 } 1645 } 1646 1647 return true; 1648 } 1649 1650 // Handler Listbox of Filter 1651 void SfxCommonTemplateDialog_Impl::EnableHierarchical(bool const bEnable) 1652 { 1653 if (bEnable) 1654 { 1655 if (!bHierarchical) 1656 { 1657 // Turn on treeView 1658 bHierarchical=true; 1659 m_bWantHierarchical = true; 1660 SaveSelection(); // fdo#61429 store "hierarchical" 1661 const OUString aSelectEntry( GetSelectedEntry()); 1662 aFmtLb->Hide(); 1663 pTreeBox->SetFont( aFmtLb->GetFont() ); 1664 pTreeBox->SetPosSizePixel(aFmtLb->GetPosPixel(), aFmtLb->GetSizePixel()); 1665 FillTreeBox(); 1666 SelectStyle(aSelectEntry); 1667 pTreeBox->Show(); 1668 } 1669 } 1670 else 1671 { 1672 pTreeBox->Hide(); 1673 aFmtLb->Show(); 1674 // If bHierarchical, then the family can have changed 1675 // minus one since hierarchical is inserted at the start 1676 m_bWantHierarchical = false; // before FilterSelect 1677 FilterSelect(aFilterLb->GetSelectedEntryPos() - 1, bHierarchical ); 1678 bHierarchical=false; 1679 } 1680 } 1681 1682 IMPL_LINK( SfxCommonTemplateDialog_Impl, FilterSelectHdl, ListBox&, rBox, void ) 1683 { 1684 if (SfxResId(STR_STYLE_FILTER_HIERARCHICAL) == rBox.GetSelectedEntry()) 1685 { 1686 EnableHierarchical(true); 1687 } 1688 else 1689 { 1690 EnableHierarchical(false); 1691 } 1692 } 1693 1694 // Select-Handler for the Toolbox 1695 void SfxCommonTemplateDialog_Impl::FamilySelect(sal_uInt16 nEntry, bool bPreviewRefresh) 1696 { 1697 assert((0 < nEntry && nEntry <= MAX_FAMILIES) || 0xffff == nEntry); 1698 if( nEntry != nActFamily || bPreviewRefresh ) 1699 { 1700 CheckItem( nActFamily, false ); 1701 nActFamily = nEntry; 1702 SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl(); 1703 SfxUInt16Item const aItem(SID_STYLE_FAMILY, 1704 static_cast<sal_uInt16>(SfxTemplate::NIdToSfxFamilyId(nEntry))); 1705 pDispat->ExecuteList(SID_STYLE_FAMILY, SfxCallMode::SYNCHRON, { &aItem }); 1706 pBindings->Invalidate( SID_STYLE_FAMILY ); 1707 pBindings->Update( SID_STYLE_FAMILY ); 1708 UpdateFamily_Impl(); 1709 } 1710 } 1711 1712 void SfxCommonTemplateDialog_Impl::ActionSelect(sal_uInt16 nEntry) 1713 { 1714 switch(nEntry) 1715 { 1716 case SID_STYLE_WATERCAN: 1717 { 1718 const bool bState = IsCheckedItem(nEntry); 1719 bool bCheck; 1720 SfxBoolItem aBool; 1721 // when a template is chosen. 1722 if (!bState && HasSelectedStyle()) 1723 { 1724 const OUString aTemplName( 1725 GetSelectedEntry()); 1726 Execute_Impl( 1727 SID_STYLE_WATERCAN, aTemplName, "", 1728 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) ); 1729 bCheck = true; 1730 } 1731 else 1732 { 1733 Execute_Impl(SID_STYLE_WATERCAN, "", "", 0); 1734 bCheck = false; 1735 } 1736 CheckItem(nEntry, bCheck); 1737 aBool.SetValue(bCheck); 1738 SetWaterCanState(&aBool); 1739 break; 1740 } 1741 case SID_STYLE_NEW_BY_EXAMPLE: 1742 { 1743 if(pStyleSheetPool && nActFamily != 0xffff) 1744 { 1745 const SfxStyleFamily eFam=GetFamilyItem_Impl()->GetFamily(); 1746 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 1747 SfxStyleSearchBits nFilter; 1748 if( pItem && nActFilter != 0xffff ) 1749 { 1750 nFilter = pItem->GetFilterList()[nActFilter].nFlags; 1751 if(nFilter == SfxStyleSearchBits::Auto) // automatic 1752 nFilter = nAppFilter; 1753 } 1754 else 1755 nFilter=pStyleSheetPool->GetSearchMask(); 1756 pStyleSheetPool->SetSearchMask( eFam, SfxStyleSearchBits::UserDefined ); 1757 1758 // why? : FloatingWindow must not be parent of a modal dialog 1759 SfxNewStyleDlg aDlg(pWindow ? pWindow->GetFrameWeld() : nullptr, *pStyleSheetPool); 1760 if (aDlg.run() == RET_OK) 1761 { 1762 pStyleSheetPool->SetSearchMask(eFam, nFilter); 1763 const OUString aTemplName(aDlg.GetName()); 1764 Execute_Impl(SID_STYLE_NEW_BY_EXAMPLE, 1765 aTemplName, "", 1766 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), 1767 nFilter); 1768 UpdateFamily_Impl(); 1769 } 1770 pStyleSheetPool->SetSearchMask( eFam, nFilter ); 1771 } 1772 break; 1773 } 1774 case SID_STYLE_UPDATE_BY_EXAMPLE: 1775 { 1776 Execute_Impl(SID_STYLE_UPDATE_BY_EXAMPLE, 1777 "", "", 1778 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily())); 1779 break; 1780 } 1781 case SID_TEMPLATE_LOAD: 1782 SfxGetpApp()->GetDispatcher_Impl()->Execute(nEntry); 1783 break; 1784 default: OSL_FAIL("not implemented"); break; 1785 } 1786 } 1787 1788 static OUString getModuleIdentifier( const Reference< XModuleManager2 >& i_xModMgr, SfxObjectShell const * i_pObjSh ) 1789 { 1790 OSL_ENSURE( i_xModMgr.is(), "getModuleIdentifier(): no XModuleManager" ); 1791 OSL_ENSURE( i_pObjSh, "getModuleIdentifier(): no ObjectShell" ); 1792 1793 OUString sIdentifier; 1794 1795 try 1796 { 1797 sIdentifier = i_xModMgr->identify( i_pObjSh->GetModel() ); 1798 } 1799 catch ( css::frame::UnknownModuleException& ) 1800 { 1801 SAL_WARN("sfx", "getModuleIdentifier(): unknown module" ); 1802 } 1803 catch ( Exception& ) 1804 { 1805 OSL_FAIL( "getModuleIdentifier(): exception of XModuleManager::identify()" ); 1806 } 1807 1808 return sIdentifier; 1809 } 1810 1811 sal_Int32 SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter( SfxObjectShell const * i_pObjSh ) 1812 { 1813 OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" ); 1814 1815 ::comphelper::SequenceAsHashMap aFactoryProps( 1816 xModuleManager->getByName( getModuleIdentifier( xModuleManager, i_pObjSh ) ) ); 1817 sal_Int32 nFilter = aFactoryProps.getUnpackedValueOrDefault( "ooSetupFactoryStyleFilter", sal_Int32(-1) ); 1818 1819 m_bWantHierarchical = (nFilter & 0x1000) != 0; 1820 nFilter &= ~0x1000; // clear it 1821 1822 return nFilter; 1823 } 1824 1825 void SfxCommonTemplateDialog_Impl::SaveFactoryStyleFilter( SfxObjectShell const * i_pObjSh, sal_Int32 i_nFilter ) 1826 { 1827 OSL_ENSURE( i_pObjSh, "SfxCommonTemplateDialog_Impl::LoadFactoryStyleFilter(): no ObjectShell" ); 1828 Sequence< PropertyValue > lProps(1); 1829 lProps[0].Name = "ooSetupFactoryStyleFilter"; 1830 lProps[0].Value <<= i_nFilter | (m_bWantHierarchical ? 0x1000 : 0); 1831 xModuleManager->replaceByName( getModuleIdentifier( xModuleManager, i_pObjSh ), makeAny( lProps ) ); 1832 } 1833 1834 SfxObjectShell* SfxCommonTemplateDialog_Impl::SaveSelection() 1835 { 1836 SfxViewFrame *const pViewFrame(pBindings->GetDispatcher_Impl()->GetFrame()); 1837 SfxObjectShell *const pDocShell(pViewFrame->GetObjectShell()); 1838 if (pDocShell) 1839 { 1840 pDocShell->SetAutoStyleFilterIndex(nActFilter); 1841 SaveFactoryStyleFilter( pDocShell, nActFilter ); 1842 } 1843 return pDocShell; 1844 } 1845 1846 IMPL_LINK( SfxCommonTemplateDialog_Impl, DropHdl, StyleTreeListBox_Impl&, rBox, bool ) 1847 { 1848 bDontUpdate = true; 1849 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 1850 const SfxStyleFamily eFam = pItem->GetFamily(); 1851 bool ret = pStyleSheetPool->SetParent(eFam, rBox.GetStyle(), rBox.GetParent()); 1852 bDontUpdate = false; 1853 return ret; 1854 } 1855 1856 // Handler for the New-Buttons 1857 void SfxCommonTemplateDialog_Impl::NewHdl() 1858 { 1859 if ( nActFamily == 0xffff || !(pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1)) 1860 return; 1861 1862 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 1863 const SfxStyleFamily eFam=pItem->GetFamily(); 1864 SfxStyleSearchBits nMask; 1865 if( nActFilter != 0xffff ) 1866 { 1867 nMask = pItem->GetFilterList()[nActFilter].nFlags; 1868 if(nMask == SfxStyleSearchBits::Auto) // automatic 1869 nMask = nAppFilter; 1870 } 1871 else 1872 nMask=pStyleSheetPool->GetSearchMask(); 1873 1874 pStyleSheetPool->SetSearchMask(eFam,nMask); 1875 1876 Execute_Impl(SID_STYLE_NEW, 1877 "", GetSelectedEntry(), 1878 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), 1879 nMask); 1880 } 1881 1882 // Handler for the edit-Buttons 1883 void SfxCommonTemplateDialog_Impl::EditHdl() 1884 { 1885 if(IsInitialized() && HasSelectedStyle()) 1886 { 1887 sal_uInt16 nFilter = nActFilter; 1888 OUString aTemplName(GetSelectedEntry()); 1889 GetSelectedStyle(); // -Wall required?? 1890 Execute_Impl( SID_STYLE_EDIT, aTemplName, OUString(), 1891 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), SfxStyleSearchBits::Auto, &nFilter ); 1892 } 1893 } 1894 1895 // Handler for the Delete-Buttons 1896 void SfxCommonTemplateDialog_Impl::DeleteHdl() 1897 { 1898 if ( !IsInitialized() || !HasSelectedStyle() ) 1899 return; 1900 1901 bool bUsedStyle = false; // one of the selected styles are used in the document? 1902 1903 std::vector<SvTreeListEntry*> aList; 1904 SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected(); 1905 const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); 1906 1907 OUStringBuffer aMsg; 1908 aMsg.append(SfxResId(STR_DELETE_STYLE_USED)).append(SfxResId(STR_DELETE_STYLE)); 1909 1910 while (pEntry) 1911 { 1912 aList.push_back( pEntry ); 1913 // check the style is used or not 1914 const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry)); 1915 1916 SfxStyleSheetBase* pStyle = pStyleSheetPool->Find( aTemplName, pItem->GetFamily() ); 1917 1918 if ( pStyle->IsUsed() ) // pStyle is in use in the document? 1919 { 1920 if (bUsedStyle) // add a separator for the second and later styles 1921 aMsg.append(", "); 1922 aMsg.append(aTemplName); 1923 bUsedStyle = true; 1924 } 1925 1926 pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry); 1927 } 1928 1929 bool aApproved = false; 1930 1931 // we only want to show the dialog once and if we want to delete a style in use (UX-advice) 1932 if ( bUsedStyle ) 1933 { 1934 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetFrameWeld(), 1935 VclMessageType::Question, VclButtonsType::YesNo, 1936 aMsg.makeStringAndClear())); 1937 aApproved = xBox->run() == RET_YES; 1938 } 1939 1940 // if there are no used styles selected or the user approved the changes 1941 if ( !(!bUsedStyle || aApproved) ) 1942 return; 1943 1944 for (auto const& elem : aList) 1945 { 1946 const OUString aTemplName(pTreeBox->IsVisible() ? pTreeBox->GetEntryText(elem) : aFmtLb->GetEntryText(elem)); 1947 bDontUpdate = true; // To prevent the Treelistbox to shut down while deleting 1948 Execute_Impl( SID_STYLE_DELETE, aTemplName, 1949 OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) ); 1950 1951 if ( pTreeBox->IsVisible() ) 1952 { 1953 pTreeBox->RemoveParentKeepChildren(elem); 1954 bDontUpdate = false; 1955 } 1956 } 1957 bDontUpdate = false; //if everything is deleted set bDontUpdate back to false 1958 UpdateStyles_Impl(StyleFlags::UpdateFamilyList); //and force-update the list 1959 } 1960 1961 void SfxCommonTemplateDialog_Impl::HideHdl() 1962 { 1963 if ( !IsInitialized() || !HasSelectedStyle() ) 1964 return; 1965 1966 SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected(); 1967 1968 while (pEntry) 1969 { 1970 OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry); 1971 1972 Execute_Impl( SID_STYLE_HIDE, aTemplName, 1973 OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) ); 1974 1975 pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry); 1976 } 1977 } 1978 1979 void SfxCommonTemplateDialog_Impl::ShowHdl() 1980 { 1981 if ( !IsInitialized() || !HasSelectedStyle() ) 1982 return; 1983 1984 SvTreeListEntry* pEntry = pTreeBox->IsVisible() ? pTreeBox->FirstSelected() : aFmtLb->FirstSelected(); 1985 1986 while (pEntry) 1987 { 1988 OUString aTemplName = pTreeBox->IsVisible() ? pTreeBox->GetEntryText(pEntry) : aFmtLb->GetEntryText(pEntry); 1989 1990 Execute_Impl( SID_STYLE_SHOW, aTemplName, 1991 OUString(), static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()) ); 1992 1993 pEntry = pTreeBox->IsVisible() ? pTreeBox->NextSelected(pEntry) : aFmtLb->NextSelected(pEntry); 1994 } 1995 } 1996 1997 void SfxCommonTemplateDialog_Impl::EnableDelete() 1998 { 1999 bool bEnableDelete(false); 2000 if(IsInitialized() && HasSelectedStyle()) 2001 { 2002 OSL_ENSURE(pStyleSheetPool, "No StyleSheetPool"); 2003 const OUString aTemplName(GetSelectedEntry()); 2004 const SfxStyleFamilyItem *pItem = GetFamilyItem_Impl(); 2005 const SfxStyleFamily eFam = pItem->GetFamily(); 2006 SfxStyleSearchBits nFilter = SfxStyleSearchBits::Auto; 2007 if (pItem->GetFilterList().size() > nActFilter) 2008 nFilter = pItem->GetFilterList()[nActFilter].nFlags; 2009 if(nFilter == SfxStyleSearchBits::Auto) // automatic 2010 nFilter = nAppFilter; 2011 const SfxStyleSheetBase *pStyle = 2012 pStyleSheetPool->Find(aTemplName,eFam, pTreeBox->IsVisible()? SfxStyleSearchBits::All : nFilter); 2013 2014 OSL_ENSURE(pStyle, "Style not found"); 2015 if (pStyle && pStyle->IsUserDefined() && (pStyle->HasParentSupport() || !pStyle->IsUsed())) 2016 bEnableDelete = true; 2017 } 2018 EnableDel(bEnableDelete); 2019 } 2020 2021 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, TreeListApplyHdl, SvTreeListBox *, bool ) 2022 { 2023 ApplyHdl(nullptr); 2024 return false; 2025 } 2026 2027 // Double-click on a style sheet in the ListBox is applied. 2028 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, ApplyHdl, LinkParamNone*, void ) 2029 { 2030 // only if that region is allowed 2031 if ( IsInitialized() && nullptr != pFamilyState[nActFamily-1] && 2032 !GetSelectedEntry().isEmpty() ) 2033 { 2034 sal_uInt16 nModifier = aFmtLb->GetModifier(); 2035 Execute_Impl(SID_STYLE_APPLY, 2036 GetSelectedEntry(), OUString(), 2037 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily()), 2038 SfxStyleSearchBits::Auto, nullptr, &nModifier ); 2039 } 2040 // After selecting a focused item if possible again on the app window 2041 if ( dynamic_cast< const SfxTemplateDialog_Impl* >(this) != nullptr ) 2042 { 2043 SfxViewFrame *pViewFrame = pBindings->GetDispatcher_Impl()->GetFrame(); 2044 SfxViewShell *pVu = pViewFrame->GetViewShell(); 2045 vcl::Window *pAppWin = pVu ? pVu->GetWindow(): nullptr; 2046 if(pAppWin) 2047 pAppWin->GrabFocus(); 2048 } 2049 } 2050 2051 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, PreviewHdl, Button*, void) 2052 { 2053 std::shared_ptr<comphelper::ConfigurationChanges> batch( comphelper::ConfigurationChanges::create() ); 2054 officecfg::Office::Common::StylesAndFormatting::Preview::set( aPreviewCheckbox->IsChecked(), batch ); 2055 batch->commit(); 2056 if(!bHierarchical) 2057 { 2058 sal_uInt16 nSize = aFmtLb->GetEntryCount(); 2059 for (sal_uInt16 nPos = 0; nPos < nSize; ++nPos ) 2060 { 2061 SvTreeListEntry* pTreeListEntry = aFmtLb->GetEntry(nPos); 2062 OUString aEntryStr = aFmtLb->GetEntryText(pTreeListEntry); 2063 const SfxStyleFamily eFam = aPreviewCheckbox->IsChecked() ? GetFamilyItem_Impl()->GetFamily(): SfxStyleFamily::None; 2064 pTreeListEntry->ReplaceItem(std::make_unique<StyleLBoxString>(aEntryStr, eFam), 1); 2065 aFmtLb->GetModel()->InvalidateEntry(pTreeListEntry); 2066 aFmtLb->Recalc(); 2067 } 2068 } 2069 else 2070 { 2071 FamilySelect(nActFamily, true); 2072 } 2073 } 2074 2075 // Selection of a template during the Watercan-Status 2076 IMPL_LINK( SfxCommonTemplateDialog_Impl, FmtSelectHdl, SvTreeListBox *, pListBox, void ) 2077 { 2078 // Trigger Help PI, if this is permitted of call handlers and field 2079 if( !pListBox || pListBox->IsSelected( pListBox->GetHdlEntry() ) ) 2080 { 2081 // Only when the watercan is on 2082 if ( IsInitialized() && 2083 IsCheckedItem(SID_STYLE_WATERCAN) && 2084 // only if that region is allowed 2085 nullptr != pFamilyState[nActFamily-1] && (pTreeBox || aFmtLb->GetSelectionCount() <= 1) ) 2086 { 2087 Execute_Impl(SID_STYLE_WATERCAN, 2088 "", "", 0); 2089 Execute_Impl(SID_STYLE_WATERCAN, 2090 GetSelectedEntry(), "", 2091 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily())); 2092 } 2093 EnableItem(SID_STYLE_WATERCAN, !bWaterDisabled); 2094 EnableDelete(); 2095 } 2096 if( !pListBox ) 2097 return; 2098 2099 SelectStyle( pListBox->GetEntryText( pListBox->GetHdlEntry() )); 2100 #if defined STYLESPREVIEW 2101 sal_uInt16 nModifier = aFmtLb->GetModifier(); 2102 if ( mbIgnoreSelect ) 2103 { 2104 Execute_Impl(SID_STYLE_END_PREVIEW, 2105 OUString(), OUString(), 2106 0, 0, 0, 0 ); 2107 mbIgnoreSelect = false; 2108 } 2109 else 2110 { 2111 Execute_Impl(SID_STYLE_PREVIEW, 2112 GetSelectedEntry(), OUString(), 2113 ( sal_uInt16 )GetFamilyItem_Impl()->GetFamily(), 2114 0, 0, &nModifier ); 2115 } 2116 #endif 2117 } 2118 2119 IMPL_LINK( SfxCommonTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool ) 2120 { 2121 sLastItemIdent = pMenu->GetCurItemIdent(); 2122 Application::PostUserEvent( 2123 LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl ) ); 2124 return true; 2125 } 2126 2127 IMPL_LINK_NOARG( SfxCommonTemplateDialog_Impl, MenuSelectAsyncHdl, void*, void ) 2128 { 2129 if (sLastItemIdent == "new") 2130 NewHdl(); 2131 else if (sLastItemIdent == "edit") 2132 EditHdl(); 2133 else if (sLastItemIdent == "delete") 2134 DeleteHdl(); 2135 else if (sLastItemIdent == "hide") 2136 HideHdl(); 2137 else if (sLastItemIdent == "show") 2138 ShowHdl(); 2139 } 2140 2141 SfxStyleFamily SfxCommonTemplateDialog_Impl::GetActualFamily() const 2142 { 2143 const SfxStyleFamilyItem *pFamilyItem = GetFamilyItem_Impl(); 2144 if( !pFamilyItem || nActFamily == 0xffff ) 2145 return SfxStyleFamily::Para; 2146 else 2147 return pFamilyItem->GetFamily(); 2148 } 2149 2150 void SfxCommonTemplateDialog_Impl::EnableExample_Impl(sal_uInt16 nId, bool bEnable) 2151 { 2152 bool bDisable = !bEnable || !IsSafeForWaterCan(); 2153 if( nId == SID_STYLE_NEW_BY_EXAMPLE ) 2154 bNewByExampleDisabled = bDisable; 2155 else if( nId == SID_STYLE_UPDATE_BY_EXAMPLE ) 2156 bUpdateByExampleDisabled = bDisable; 2157 2158 EnableItem(nId, bEnable); 2159 } 2160 2161 VclPtr<PopupMenu> const & SfxCommonTemplateDialog_Impl::CreateContextMenu() 2162 { 2163 if ( bBindingUpdate ) 2164 { 2165 pBindings->Invalidate( SID_STYLE_NEW, true ); 2166 pBindings->Update( SID_STYLE_NEW ); 2167 bBindingUpdate = false; 2168 } 2169 mxMenu.disposeAndClear(); 2170 mxBuilder.reset(new VclBuilder(nullptr, VclBuilderContainer::getUIRootDir(), "sfx/ui/stylecontextmenu.ui", "")); 2171 mxMenu.set(mxBuilder->get_menu("menu")); 2172 mxMenu->SetMenuFlags(MenuFlags::AlwaysShowDisabledEntries); 2173 mxMenu->SetSelectHdl( LINK( this, SfxCommonTemplateDialog_Impl, MenuSelectHdl ) ); 2174 mxMenu->EnableItem(mxMenu->GetItemId("edit"), bCanEdit); 2175 mxMenu->EnableItem(mxMenu->GetItemId("delete"), bCanDel); 2176 mxMenu->EnableItem(mxMenu->GetItemId("new"), bCanNew); 2177 mxMenu->EnableItem(mxMenu->GetItemId("hide"), bCanHide); 2178 mxMenu->EnableItem(mxMenu->GetItemId("show"), bCanShow); 2179 2180 const SfxStyleFamilyItem* pItem = GetFamilyItem_Impl(); 2181 if (pItem && pItem->GetFamily() == SfxStyleFamily::Table) //tdf#101648, no ui for this yet 2182 { 2183 mxMenu->EnableItem(mxMenu->GetItemId("edit"), false); 2184 mxMenu->EnableItem(mxMenu->GetItemId("new"), false); 2185 } 2186 2187 return mxMenu; 2188 } 2189 2190 SfxTemplateDialog_Impl::SfxTemplateDialog_Impl(SfxBindings* pB, SfxTemplatePanelControl* pDlgWindow) 2191 : SfxCommonTemplateDialog_Impl(pB, pDlgWindow) 2192 , m_pFloat(pDlgWindow) 2193 , m_aActionTbL(VclPtrInstance<DropToolBox_Impl>(pDlgWindow, this)) 2194 , m_aActionTbR(VclPtrInstance<ToolBox>(pDlgWindow)) 2195 { 2196 m_aActionTbR->InsertItem(SID_STYLE_WATERCAN, Image(StockImage::Yes, RID_SFXBMP_WATERCAN), SfxResId(STR_STYLE_FILL_FORMAT_MODE)); 2197 m_aActionTbR->SetHelpId(SID_STYLE_WATERCAN, HID_TEMPLDLG_WATERCAN); 2198 2199 m_aActionTbR->InsertItem(SID_STYLE_NEW_BY_EXAMPLE, Image(StockImage::Yes, RID_SFXBMP_NEW_BY_EXAMPLE), SfxResId(STR_STYLE_NEW_STYLE_FROM_SELECTION)); 2200 //renamed to SID_STYLE_NEW_BY_EXAMPLE in SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu() 2201 m_aActionTbR->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE); 2202 2203 m_aActionTbR->InsertItem(SID_STYLE_UPDATE_BY_EXAMPLE, Image(StockImage::Yes, RID_SFXBMP_UPDATE_BY_EXAMPLE), SfxResId(STR_STYLE_UPDATE_STYLE)); 2204 m_aActionTbR->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE); 2205 2206 Initialize(); 2207 } 2208 2209 void SfxTemplateDialog_Impl::Initialize() 2210 { 2211 SfxCommonTemplateDialog_Impl::Initialize(); 2212 2213 m_aActionTbL->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxLSelect)); 2214 m_aActionTbR->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRSelect)); 2215 m_aActionTbR->SetDropdownClickHdl(LINK(this, SfxTemplateDialog_Impl, ToolBoxRClick)); 2216 m_aActionTbL->Show(); 2217 m_aActionTbR->Show(); 2218 vcl::Font aFont = aFilterLb->GetFont(); 2219 aFont.SetWeight( WEIGHT_NORMAL ); 2220 aFilterLb->SetFont( aFont ); 2221 m_aActionTbL->SetHelpId( HID_TEMPLDLG_TOOLBOX_LEFT ); 2222 } 2223 2224 void SfxTemplateDialog_Impl::EnableFamilyItem( sal_uInt16 nId, bool bEnable ) 2225 { 2226 m_aActionTbL->EnableItem( nId, bEnable ); 2227 } 2228 2229 // Insert element into dropdown filter "Frame Styles", "List Styles", etc. 2230 void SfxTemplateDialog_Impl::InsertFamilyItem(sal_uInt16 nId,const SfxStyleFamilyItem &rItem) 2231 { 2232 OString sHelpId; 2233 switch( rItem.GetFamily() ) 2234 { 2235 case SfxStyleFamily::Char: sHelpId = ".uno:CharStyle"; break; 2236 case SfxStyleFamily::Para: sHelpId = ".uno:ParaStyle"; break; 2237 case SfxStyleFamily::Frame: sHelpId = ".uno:FrameStyle"; break; 2238 case SfxStyleFamily::Page: sHelpId = ".uno:PageStyle"; break; 2239 case SfxStyleFamily::Pseudo: sHelpId = ".uno:ListStyle"; break; 2240 case SfxStyleFamily::Table: sHelpId = ".uno:TableStyle"; break; 2241 default: OSL_FAIL("unknown StyleFamily"); break; 2242 } 2243 m_aActionTbL->InsertItem( nId, rItem.GetImage(), rItem.GetText(), ToolBoxItemBits::NONE, 0); 2244 m_aActionTbL->SetHelpId( nId, sHelpId ); 2245 } 2246 2247 void SfxTemplateDialog_Impl::ReplaceUpdateButtonByMenu() 2248 { 2249 m_aActionTbR->HideItem(SID_STYLE_UPDATE_BY_EXAMPLE); 2250 m_aActionTbR->SetItemBits( SID_STYLE_NEW_BY_EXAMPLE, 2251 ToolBoxItemBits::DROPDOWNONLY|m_aActionTbR->GetItemBits( SID_STYLE_NEW_BY_EXAMPLE )); 2252 //rename menu in case of Writer 2253 m_aActionTbR->SetItemText(SID_STYLE_NEW_BY_EXAMPLE, SfxResId(STR_STYLE_NEW_STYLE_ACTION)); 2254 } 2255 2256 void SfxTemplateDialog_Impl::ClearFamilyList() 2257 { 2258 m_aActionTbL->Clear(); 2259 } 2260 2261 void SfxCommonTemplateDialog_Impl::InvalidateBindings() 2262 { 2263 pBindings->Invalidate(SID_STYLE_NEW_BY_EXAMPLE, true); 2264 pBindings->Update( SID_STYLE_NEW_BY_EXAMPLE ); 2265 pBindings->Invalidate(SID_STYLE_UPDATE_BY_EXAMPLE, true); 2266 pBindings->Update( SID_STYLE_UPDATE_BY_EXAMPLE ); 2267 pBindings->Invalidate( SID_STYLE_WATERCAN, true); 2268 pBindings->Update( SID_STYLE_WATERCAN ); 2269 pBindings->Invalidate( SID_STYLE_NEW, true); 2270 pBindings->Update( SID_STYLE_NEW ); 2271 pBindings->Invalidate( SID_STYLE_DRAGHIERARCHIE, true); 2272 pBindings->Update( SID_STYLE_DRAGHIERARCHIE ); 2273 } 2274 2275 SfxTemplateDialog_Impl::~SfxTemplateDialog_Impl() 2276 { 2277 m_pFloat.clear(); 2278 m_aActionTbL.disposeAndClear(); 2279 m_aActionTbR.disposeAndClear(); 2280 } 2281 2282 void SfxTemplateDialog_Impl::LoadedFamilies() 2283 { 2284 Resize(); 2285 } 2286 2287 // Override Resize-Handler ( StarView ) 2288 // The size of the Listboxen is adjusted 2289 void SfxTemplateDialog_Impl::Resize() 2290 { 2291 if (m_pFloat == nullptr) 2292 return; 2293 Size aDlgSize=m_pFloat->PixelToLogic(m_pFloat->GetOutputSizePixel()); 2294 Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel()); 2295 Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel()); 2296 Size aMinSize = GetMinOutputSizePixel(); 2297 2298 long nListHeight = m_pFloat->PixelToLogic( aFilterLb->GetSizePixel() ).Height(); 2299 long nWidth = aDlgSize.Width()- 2 * SFX_TEMPLDLG_HFRAME; 2300 2301 m_aActionTbL->SetPosSizePixel(m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME,SFX_TEMPLDLG_VTOPFRAME)), 2302 m_pFloat->LogicToPixel(aSizeATL)); 2303 2304 // only change the position of the right toolbox, when the window is wide 2305 // enough 2306 Point aPosATR(aDlgSize.Width()-SFX_TEMPLDLG_HFRAME-aSizeATR.Width(),SFX_TEMPLDLG_VTOPFRAME); 2307 if(aDlgSize.Width() >= aMinSize.Width()) 2308 m_aActionTbR->SetPosPixel(m_pFloat->LogicToPixel(aPosATR)); 2309 else 2310 m_aActionTbR->SetPosPixel( m_pFloat->LogicToPixel( 2311 Point( SFX_TEMPLDLG_HFRAME + aSizeATL.Width() + SFX_TEMPLDLG_MIDHSPACE, 2312 SFX_TEMPLDLG_VTOPFRAME ) ) ); 2313 2314 m_aActionTbR->SetSizePixel(m_pFloat->LogicToPixel(aSizeATR)); 2315 2316 Point aFilterPos( 2317 m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME, 2318 aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-nListHeight)) ); 2319 2320 Size aFilterSize( 2321 m_pFloat->LogicToPixel(Size(nWidth,SFX_TEMPLDLG_FILTERHEIGHT)) ); 2322 2323 Point aCheckBoxPos( 2324 m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME, 2325 aDlgSize.Height()-SFX_TEMPLDLG_VBOTFRAME-2*nListHeight)) ); 2326 2327 Size aCheckBoxSize( 2328 m_pFloat->LogicToPixel(Size(nWidth, nListHeight)) ); 2329 2330 Point aFmtPos( 2331 m_pFloat->LogicToPixel(Point(SFX_TEMPLDLG_HFRAME, SFX_TEMPLDLG_VTOPFRAME + 2332 SFX_TEMPLDLG_MIDVSPACE+aSizeATL.Height())) ); 2333 Size aFmtSize( 2334 m_pFloat->LogicToPixel(Size(nWidth, 2335 aDlgSize.Height() - SFX_TEMPLDLG_VBOTFRAME - 2336 SFX_TEMPLDLG_VTOPFRAME - 2*SFX_TEMPLDLG_MIDVSPACE- 2337 2*nListHeight-aSizeATL.Height())) ); 2338 2339 // only change the position of the listbox, when the window is high enough 2340 if(aDlgSize.Height() >= aMinSize.Height()) 2341 { 2342 aFilterLb->SetPosPixel(aFilterPos); 2343 aFmtLb->SetPosPixel( aFmtPos ); 2344 aPreviewCheckbox->SetPosPixel(aCheckBoxPos); 2345 if(pTreeBox->IsVisible()) 2346 pTreeBox->SetPosPixel(aFmtPos); 2347 } 2348 else 2349 aFmtSize.AdjustHeight(aFilterSize.Height() ); 2350 2351 aFilterLb->SetSizePixel(aFilterSize); 2352 aFmtLb->SetSizePixel( aFmtSize ); 2353 aPreviewCheckbox->SetSizePixel( aCheckBoxSize ); 2354 if(pTreeBox->IsVisible()) 2355 pTreeBox->SetSizePixel(aFmtSize); 2356 } 2357 2358 Size SfxTemplateDialog_Impl::GetMinOutputSizePixel() 2359 { 2360 if (m_pFloat != nullptr) 2361 { 2362 Size aSizeATL=m_pFloat->PixelToLogic(m_aActionTbL->CalcWindowSizePixel()); 2363 Size aSizeATR=m_pFloat->PixelToLogic(m_aActionTbR->CalcWindowSizePixel()); 2364 Size aMinSize( 2365 aSizeATL.Width()+aSizeATR.Width()+ 2366 2*SFX_TEMPLDLG_HFRAME + SFX_TEMPLDLG_MIDHSPACE, 2367 4*aSizeATL.Height()+2*SFX_TEMPLDLG_MIDVSPACE); 2368 return aMinSize; 2369 } 2370 else 2371 return Size(0,0); 2372 } 2373 2374 void SfxTemplateDialog_Impl::EnableItem(sal_uInt16 nMesId, bool bCheck) 2375 { 2376 switch(nMesId) 2377 { 2378 case SID_STYLE_WATERCAN : 2379 if(!bCheck && IsCheckedItem(SID_STYLE_WATERCAN)) 2380 Execute_Impl(SID_STYLE_WATERCAN, "", "", 0); 2381 [[fallthrough]]; 2382 case SID_STYLE_NEW_BY_EXAMPLE: 2383 case SID_STYLE_UPDATE_BY_EXAMPLE: 2384 m_aActionTbR->EnableItem(nMesId,bCheck); 2385 break; 2386 } 2387 } 2388 2389 void SfxTemplateDialog_Impl::CheckItem(sal_uInt16 nMesId, bool bCheck) 2390 { 2391 switch(nMesId) 2392 { 2393 case SID_STYLE_WATERCAN : 2394 bIsWater=bCheck; 2395 m_aActionTbR->CheckItem(SID_STYLE_WATERCAN,bCheck); 2396 break; 2397 default: 2398 m_aActionTbL->CheckItem(nMesId,bCheck); break; 2399 } 2400 } 2401 2402 bool SfxTemplateDialog_Impl::IsCheckedItem(sal_uInt16 nMesId) 2403 { 2404 switch(nMesId) 2405 { 2406 case SID_STYLE_WATERCAN : 2407 return m_aActionTbR->GetItemState(SID_STYLE_WATERCAN)==TRISTATE_TRUE; 2408 default: 2409 return m_aActionTbL->GetItemState(nMesId)==TRISTATE_TRUE; 2410 } 2411 } 2412 2413 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxLSelect, ToolBox *, pBox, void ) 2414 { 2415 const sal_uInt16 nEntry = pBox->GetCurItemId(); 2416 FamilySelect(nEntry); 2417 } 2418 2419 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRSelect, ToolBox *, pBox, void ) 2420 { 2421 const sal_uInt16 nEntry = pBox->GetCurItemId(); 2422 if(nEntry != SID_STYLE_NEW_BY_EXAMPLE || 2423 ToolBoxItemBits::DROPDOWN != (pBox->GetItemBits(nEntry)&ToolBoxItemBits::DROPDOWN)) 2424 ActionSelect(nEntry); 2425 } 2426 2427 IMPL_LINK( SfxTemplateDialog_Impl, ToolBoxRClick, ToolBox *, pBox, void ) 2428 { 2429 const sal_uInt16 nEntry = pBox->GetCurItemId(); 2430 if(nEntry != SID_STYLE_NEW_BY_EXAMPLE || 2431 !(pBox->GetItemBits(nEntry) & ToolBoxItemBits::DROPDOWN)) 2432 return; 2433 2434 //create a popup menu in Writer 2435 ScopedVclPtrInstance<PopupMenu> pMenu; 2436 OUString sTextDoc("com.sun.star.text.TextDocument"); 2437 2438 auto aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleNewByExample", sTextDoc); 2439 OUString sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties); 2440 pMenu->InsertItem( SID_STYLE_NEW_BY_EXAMPLE, sLabel ); 2441 pMenu->SetHelpId(SID_STYLE_NEW_BY_EXAMPLE, HID_TEMPLDLG_NEWBYEXAMPLE); 2442 2443 aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:StyleUpdateByExample", sTextDoc); 2444 sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties); 2445 pMenu->InsertItem( SID_STYLE_UPDATE_BY_EXAMPLE, sLabel ); 2446 pMenu->SetHelpId(SID_STYLE_UPDATE_BY_EXAMPLE, HID_TEMPLDLG_UPDATEBYEXAMPLE); 2447 2448 pMenu->InsertSeparator(); 2449 2450 aProperties = vcl::CommandInfoProvider::GetCommandProperties(".uno:LoadStyles", sTextDoc); 2451 sLabel = vcl::CommandInfoProvider::GetPopupLabelForCommand(aProperties); 2452 pMenu->InsertItem( SID_TEMPLATE_LOAD, sLabel ); 2453 pMenu->SetHelpId(SID_TEMPLATE_LOAD, ".uno:LoadStyles"); 2454 2455 pMenu->SetSelectHdl(LINK(this, SfxTemplateDialog_Impl, MenuSelectHdl)); 2456 pMenu->Execute( pBox, 2457 pBox->GetItemRect(nEntry), 2458 PopupMenuFlags::ExecuteDown ); 2459 pBox->EndSelection(); 2460 pBox->Invalidate(); 2461 } 2462 2463 IMPL_LINK( SfxTemplateDialog_Impl, MenuSelectHdl, Menu*, pMenu, bool) 2464 { 2465 sal_uInt16 nMenuId = pMenu->GetCurItemId(); 2466 ActionSelect(nMenuId); 2467 return false; 2468 } 2469 2470 void SfxCommonTemplateDialog_Impl::SetFamily(SfxStyleFamily const nFamily) 2471 { 2472 sal_uInt16 const nId(SfxTemplate::SfxFamilyIdToNId(nFamily)); 2473 assert((0 < nId && nId <= MAX_FAMILIES) || 0xffff == nId); 2474 if ( nId != nActFamily ) 2475 { 2476 if ( nActFamily != 0xFFFF ) 2477 CheckItem( nActFamily, false ); 2478 nActFamily = nId; 2479 if ( nId != 0xFFFF ) 2480 bUpdateFamily = true; 2481 } 2482 } 2483 2484 void SfxCommonTemplateDialog_Impl::UpdateFamily_Impl() 2485 { 2486 bUpdateFamily = false; 2487 2488 SfxDispatcher* pDispat = pBindings->GetDispatcher_Impl(); 2489 SfxViewFrame *pViewFrame = pDispat->GetFrame(); 2490 SfxObjectShell *pDocShell = pViewFrame->GetObjectShell(); 2491 2492 SfxStyleSheetBasePool *pOldStyleSheetPool = pStyleSheetPool; 2493 pStyleSheetPool = pDocShell? pDocShell->GetStyleSheetPool(): nullptr; 2494 if ( pOldStyleSheetPool != pStyleSheetPool ) 2495 { 2496 if ( pOldStyleSheetPool ) 2497 EndListening(*pOldStyleSheetPool); 2498 if ( pStyleSheetPool ) 2499 StartListening(*pStyleSheetPool); 2500 } 2501 2502 bWaterDisabled = false; 2503 bCanNew = pTreeBox->IsVisible() || aFmtLb->GetSelectionCount() <= 1; 2504 bTreeDrag = true; 2505 bUpdateByExampleDisabled = false; 2506 2507 if (pStyleSheetPool) 2508 { 2509 if (!pTreeBox->IsVisible()) 2510 UpdateStyles_Impl(StyleFlags::UpdateFamily | StyleFlags::UpdateFamilyList); 2511 else 2512 { 2513 UpdateStyles_Impl(StyleFlags::UpdateFamily); 2514 FillTreeBox(); 2515 } 2516 } 2517 2518 InvalidateBindings(); 2519 2520 if (IsCheckedItem(SID_STYLE_WATERCAN) && 2521 // only if that area is allowed 2522 nullptr != pFamilyState[nActFamily - 1]) 2523 { 2524 Execute_Impl(SID_STYLE_APPLY, 2525 GetSelectedEntry(), 2526 OUString(), 2527 static_cast<sal_uInt16>(GetFamilyItem_Impl()->GetFamily())); 2528 } 2529 } 2530 2531 void SfxCommonTemplateDialog_Impl::ReplaceUpdateButtonByMenu() 2532 { 2533 //does nothing 2534 } 2535 2536 DropToolBox_Impl::DropToolBox_Impl(vcl::Window* pParent, SfxTemplateDialog_Impl* pTemplateDialog) : 2537 ToolBox(pParent), 2538 DropTargetHelper(this), 2539 rParent(*pTemplateDialog) 2540 { 2541 } 2542 2543 sal_Int8 DropToolBox_Impl::AcceptDrop( const AcceptDropEvent& rEvt ) 2544 { 2545 sal_Int8 nReturn = DND_ACTION_NONE; 2546 sal_uInt16 nItemId = GetItemId( rEvt.maPosPixel ); 2547 if(USHRT_MAX != nItemId && !IsItemChecked( nItemId )) 2548 { 2549 SetCurItemId(nItemId); 2550 GetSelectHdl().Call(this); 2551 } 2552 // special case: page styles are allowed to create new styles by example 2553 // but not allowed to be created by drag and drop 2554 if ( nItemId != SfxTemplate::SfxFamilyIdToNId( SfxStyleFamily::Page )&& 2555 IsDropFormatSupported( SotClipboardFormatId::OBJECTDESCRIPTOR ) && 2556 !rParent.bNewByExampleDisabled ) 2557 { 2558 nReturn = DND_ACTION_COPY; 2559 } 2560 return nReturn; 2561 } 2562 2563 sal_Int8 DropToolBox_Impl::ExecuteDrop( const ExecuteDropEvent& rEvt ) 2564 { 2565 return rParent.aFmtLb->ExecuteDrop(rEvt); 2566 } 2567 2568 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 2569
