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 10 #include <sfx2/templatelocalview.hxx> 11 12 #include <comphelper/string.hxx> 13 #include <sfx2/doctempl.hxx> 14 #include <sfx2/inputdlg.hxx> 15 #include <sfx2/sfxresid.hxx> 16 #include <templatecontaineritem.hxx> 17 #include <templateviewitem.hxx> 18 #include <sfx2/docfac.hxx> 19 #include <tools/urlobj.hxx> 20 #include <unotools/moduleoptions.hxx> 21 #include <vcl/svapp.hxx> 22 #include <vcl/weld.hxx> 23 #include <vcl/commandevent.hxx> 24 #include <vcl/event.hxx> 25 26 #include <sfx2/strings.hrc> 27 #include <bitmaps.hlst> 28 29 using namespace ::com::sun::star; 30 31 bool ViewFilter_Application::isFilteredExtension(FILTER_APPLICATION filter, std::u16string_view rExt) 32 { 33 bool bRet = rExt == u"ott" || rExt == u"stw" || rExt == u"oth" || rExt == u"dot" || rExt == u"dotx" || rExt == u"otm" 34 || rExt == u"ots" || rExt == u"stc" || rExt == u"xlt" || rExt == u"xltm" || rExt == u"xltx" 35 || rExt == u"otp" || rExt == u"sti" || rExt == u"pot" || rExt == u"potm" || rExt == u"potx" 36 || rExt == u"otg" || rExt == u"std"; 37 38 if (filter == FILTER_APPLICATION::WRITER) 39 { 40 bRet = rExt == u"ott" || rExt == u"stw" || rExt == u"oth" || rExt == u"dot" || rExt == u"dotx" || rExt == u"otm"; 41 } 42 else if (filter == FILTER_APPLICATION::CALC) 43 { 44 bRet = rExt == u"ots" || rExt == u"stc" || rExt == u"xlt" || rExt == u"xltm" || rExt == u"xltx"; 45 } 46 else if (filter == FILTER_APPLICATION::IMPRESS) 47 { 48 bRet = rExt == u"otp" || rExt == u"sti" || rExt == u"pot" || rExt == u"potm" || rExt == u"potx"; 49 } 50 else if (filter == FILTER_APPLICATION::DRAW) 51 { 52 bRet = rExt == u"otg" || rExt == u"std"; 53 } 54 55 return bRet; 56 } 57 58 bool ViewFilter_Application::isValid (const OUString &rPath) const 59 { 60 INetURLObject aUrl(rPath); 61 return isFilteredExtension(mApp, aUrl.getExtension()); 62 } 63 64 bool ViewFilter_Application::operator () (const ThumbnailViewItem *pItem) 65 { 66 const TemplateViewItem *pTempItem = dynamic_cast<const TemplateViewItem*>(pItem); 67 if (pTempItem) 68 return isValid(pTempItem->getPath()); 69 70 return true; 71 } 72 73 void TemplateLocalView::updateThumbnailDimensions(tools::Long itemMaxSize) 74 { 75 mnThumbnailWidth = itemMaxSize; 76 mnThumbnailHeight = itemMaxSize; 77 } 78 79 TemplateLocalView::TemplateLocalView(std::unique_ptr<weld::ScrolledWindow> xWindow, 80 std::unique_ptr<weld::Menu> xMenu) 81 : ThumbnailView(std::move(xWindow), std::move(xMenu)) 82 , mnCurRegionId(0) 83 , maSelectedItem(nullptr) 84 , mnThumbnailWidth(TEMPLATE_THUMBNAIL_MAX_WIDTH) 85 , mnThumbnailHeight(TEMPLATE_THUMBNAIL_MAX_HEIGHT) 86 , maPosition(0,0) 87 , mpDocTemplates(new SfxDocumentTemplates) 88 { 89 } 90 91 TemplateLocalView::~TemplateLocalView() 92 { 93 } 94 95 void TemplateLocalView::Populate() 96 { 97 maRegions.clear(); 98 maAllTemplates.clear(); 99 100 sal_uInt16 nCount = mpDocTemplates->GetRegionCount(); 101 for (sal_uInt16 i = 0; i < nCount; ++i) 102 { 103 OUString aRegionName(mpDocTemplates->GetFullRegionName(i)); 104 105 std::unique_ptr<TemplateContainerItem> pItem(new TemplateContainerItem( i+1 )); 106 pItem->mnRegionId = i; 107 pItem->maTitle = aRegionName; 108 109 sal_uInt16 nEntries = mpDocTemplates->GetCount(i); 110 111 for (sal_uInt16 j = 0; j < nEntries; ++j) 112 { 113 OUString aName = mpDocTemplates->GetName(i,j); 114 OUString aURL = mpDocTemplates->GetPath(i,j); 115 116 TemplateItemProperties aProperties; 117 aProperties.nId = j+1; 118 aProperties.nDocId = j; 119 aProperties.nRegionId = i; 120 aProperties.aName = aName; 121 aProperties.aPath = aURL; 122 aProperties.aRegionName = aRegionName; 123 aProperties.aThumbnail = TemplateLocalView::fetchThumbnail(aURL, 124 mnThumbnailWidth, 125 mnThumbnailHeight); 126 127 pItem->maTemplates.push_back(aProperties); 128 maAllTemplates.push_back(aProperties); 129 } 130 131 maRegions.push_back(std::move(pItem)); 132 } 133 } 134 135 void TemplateLocalView::reload() 136 { 137 mpDocTemplates->Update(); 138 139 Populate(); 140 141 // Check if we are currently browsing a region or root folder 142 if (mnCurRegionId) 143 { 144 sal_uInt16 nRegionId = mnCurRegionId - 1; //Is offset by 1 145 146 for (auto const & pRegion : maRegions) 147 { 148 if (pRegion->mnRegionId == nRegionId) 149 { 150 showRegion(pRegion.get()); 151 break; 152 } 153 } 154 } 155 else 156 showAllTemplates(); 157 158 //No items should be selected by default 159 deselectItems(); 160 } 161 162 void TemplateLocalView::showAllTemplates() 163 { 164 mnCurRegionId = 0; 165 166 insertItems(maAllTemplates, false, true); 167 168 maOpenRegionHdl.Call(nullptr); 169 } 170 171 void TemplateLocalView::showRegion(TemplateContainerItem const *pItem) 172 { 173 mnCurRegionId = pItem->mnRegionId+1; 174 175 insertItems(pItem->maTemplates); 176 177 maOpenRegionHdl.Call(nullptr); 178 } 179 180 TemplateContainerItem* TemplateLocalView::getRegion(std::u16string_view rName) 181 { 182 for (auto const & pRegion : maRegions) 183 if (pRegion->maTitle == rName) 184 return pRegion.get(); 185 186 return nullptr; 187 } 188 189 void TemplateLocalView::ContextMenuSelectHdl(std::string_view rIdent) 190 { 191 if (rIdent == "open") 192 maOpenTemplateHdl.Call(maSelectedItem); 193 else if (rIdent == "edit") 194 maEditTemplateHdl.Call(maSelectedItem); 195 else if (rIdent == "rename") 196 { 197 InputDialog aTitleEditDlg(GetDrawingArea(), SfxResId(STR_RENAME_TEMPLATE)); 198 OUString sOldTitle = maSelectedItem->getTitle(); 199 aTitleEditDlg.SetEntryText(sOldTitle); 200 aTitleEditDlg.HideHelpBtn(); 201 202 if (!aTitleEditDlg.run()) 203 return; 204 OUString sNewTitle = comphelper::string::strip(aTitleEditDlg.GetEntryText(), ' '); 205 206 if ( !sNewTitle.isEmpty() && sNewTitle != sOldTitle ) 207 { 208 maSelectedItem->setTitle(sNewTitle); 209 } 210 } 211 else if (rIdent == "delete") 212 { 213 std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, 214 SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); 215 if (xQueryDlg->run() != RET_YES) 216 return; 217 218 maDeleteTemplateHdl.Call(maSelectedItem); 219 reload(); 220 } 221 else if (rIdent == "default") 222 maDefaultTemplateHdl.Call(maSelectedItem); 223 } 224 225 sal_uInt16 TemplateLocalView::getRegionId(size_t pos) const 226 { 227 assert(pos < maRegions.size()); 228 229 return maRegions[pos]->mnId; 230 } 231 232 sal_uInt16 TemplateLocalView::getRegionId(std::u16string_view sRegion) const 233 { 234 for (auto const & pRegion : maRegions) 235 { 236 if (pRegion->maTitle == sRegion) 237 return pRegion->mnId; 238 } 239 240 return 0; 241 } 242 243 OUString TemplateLocalView::getRegionName(const sal_uInt16 nRegionId) const 244 { 245 return mpDocTemplates->GetRegionName(nRegionId); 246 } 247 248 OUString TemplateLocalView::getRegionItemName(const sal_uInt16 nItemId) const 249 { 250 for (auto const & pRegion : maRegions) 251 { 252 if (pRegion->mnId == nItemId) 253 return pRegion->maTitle; 254 } 255 256 return OUString(); 257 } 258 259 std::vector<OUString> TemplateLocalView::getFolderNames() 260 { 261 size_t n = maRegions.size(); 262 std::vector<OUString> ret(n); 263 264 for (size_t i = 0; i < n; ++i) 265 ret[i] = maRegions[i]->maTitle; 266 267 return ret; 268 } 269 270 std::vector<TemplateItemProperties> 271 TemplateLocalView::getFilteredItems(const std::function<bool (const TemplateItemProperties&)> &rFunc) const 272 { 273 std::vector<TemplateItemProperties> aItems; 274 275 if (mnCurRegionId) 276 { 277 TemplateContainerItem *pFolderItem = maRegions[mnCurRegionId-1].get(); 278 279 for (const TemplateItemProperties & rItemProps : pFolderItem->maTemplates) 280 { 281 if (rFunc(rItemProps)) 282 aItems.push_back(rItemProps); 283 } 284 } 285 else 286 { 287 for (auto const & pFolderItem : maRegions) 288 { 289 for (const TemplateItemProperties & rItemProps : pFolderItem->maTemplates) 290 { 291 if (rFunc(rItemProps)) 292 aItems.push_back(rItemProps); 293 } 294 } 295 } 296 297 return aItems; 298 } 299 300 sal_uInt16 TemplateLocalView::createRegion(const OUString &rName) 301 { 302 sal_uInt16 nRegionId = mpDocTemplates->GetRegionCount(); // Next regionId 303 sal_uInt16 nItemId = getNextItemId(); 304 305 if (!mpDocTemplates->InsertDir(rName,nRegionId)) 306 return 0; 307 308 // Insert to the region cache list and to the thumbnail item list 309 std::unique_ptr<TemplateContainerItem> pItem(new TemplateContainerItem( nItemId )); 310 pItem->mnRegionId = nRegionId; 311 pItem->maTitle = rName; 312 313 maRegions.push_back(std::move(pItem)); 314 315 return nItemId; 316 } 317 318 bool TemplateLocalView::renameRegion(std::u16string_view rTitle, const OUString &rNewTitle) 319 { 320 TemplateContainerItem *pRegion = getRegion(rTitle); 321 322 if(pRegion) 323 { 324 sal_uInt16 nRegionId = pRegion->mnRegionId; 325 return mpDocTemplates->SetName( rNewTitle, nRegionId, USHRT_MAX/*nDocId*/ ); 326 } 327 return false; 328 } 329 330 bool TemplateLocalView::removeRegion(const sal_uInt16 nItemId) 331 { 332 sal_uInt16 nRegionId = USHRT_MAX; 333 334 // Remove from the region cache list 335 for (auto pRegionIt = maRegions.begin(); pRegionIt != maRegions.end();) 336 { 337 if ( (*pRegionIt)->mnId == nItemId ) 338 { 339 if (!mpDocTemplates->Delete((*pRegionIt)->mnRegionId,USHRT_MAX)) 340 return false; 341 342 nRegionId = (*pRegionIt)->mnRegionId; 343 344 pRegionIt = maRegions.erase(pRegionIt); 345 } 346 else 347 { 348 // Synchronize regions cache ids with SfxDocumentTemplates 349 if (nRegionId != USHRT_MAX && (*pRegionIt)->mnRegionId > nRegionId) 350 --(*pRegionIt)->mnRegionId; 351 352 ++pRegionIt; 353 } 354 } 355 356 if (nRegionId == USHRT_MAX) 357 return false; 358 359 // Synchronize view regions ids with SfxDocumentTemplates 360 for (auto const& region : maRegions) 361 { 362 if (region->mnRegionId > nRegionId) 363 --region->mnRegionId; 364 } 365 366 return true; 367 } 368 369 bool TemplateLocalView::removeTemplate (const sal_uInt16 nItemId, const sal_uInt16 nSrcItemId) 370 { 371 for (auto const & pRegion : maRegions) 372 { 373 if (pRegion->mnId == nSrcItemId) 374 { 375 TemplateContainerItem *pItem = pRegion.get(); 376 auto pIter = std::find_if(pItem->maTemplates.begin(), pItem->maTemplates.end(), 377 [nItemId](const TemplateItemProperties& rTemplate) { return rTemplate.nId == nItemId; }); 378 if (pIter != pItem->maTemplates.end()) 379 { 380 if (!mpDocTemplates->Delete(pItem->mnRegionId,pIter->nDocId)) 381 return false; 382 383 pIter = pItem->maTemplates.erase(pIter); 384 385 if (pRegion->mnRegionId == mnCurRegionId-1) 386 { 387 RemoveItem(nItemId); 388 Invalidate(); 389 } 390 391 // Update Doc Idx for all templates that follow 392 for (; pIter != pItem->maTemplates.end(); ++pIter) 393 pIter->nDocId = pIter->nDocId - 1; 394 } 395 396 CalculateItemPositions(); 397 break; 398 } 399 } 400 401 return true; 402 } 403 404 bool TemplateLocalView::moveTemplate (const ThumbnailViewItem *pItem, const sal_uInt16 nSrcItem, 405 const sal_uInt16 nTargetItem) 406 { 407 TemplateContainerItem *pTarget = nullptr; 408 TemplateContainerItem *pSrc = nullptr; 409 410 for (auto const & pRegion : maRegions) 411 { 412 if (pRegion->mnId == nTargetItem) 413 pTarget = pRegion.get(); 414 else if (pRegion->mnId == nSrcItem) 415 pSrc = pRegion.get(); 416 } 417 418 if (pTarget && pSrc) 419 { 420 sal_uInt16 nSrcRegionId = pSrc->mnRegionId; 421 sal_uInt16 nTargetRegion = pTarget->mnRegionId; 422 sal_uInt16 nTargetIdx = mpDocTemplates->GetCount(nTargetRegion); // Next Idx 423 424 const TemplateViewItem *pViewItem = static_cast<const TemplateViewItem*>(pItem); 425 426 bool bCopy = !mpDocTemplates->Move(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId); 427 428 if (bCopy) 429 { 430 OUString sQuery = SfxResId(STR_MSG_QUERY_COPY).replaceFirst("$1", pViewItem->maTitle).replaceFirst("$2", 431 getRegionName(nTargetRegion)); 432 433 std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, sQuery)); 434 if (xQueryDlg->run() != RET_YES) 435 return false; 436 437 if (!mpDocTemplates->Copy(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId)) 438 return false; 439 } 440 // move template to destination 441 442 TemplateItemProperties aTemplateItem; 443 aTemplateItem.nId = nTargetIdx + 1; 444 aTemplateItem.nDocId = nTargetIdx; 445 aTemplateItem.nRegionId = nTargetRegion; 446 aTemplateItem.aName = pViewItem->maTitle; 447 aTemplateItem.aPath = mpDocTemplates->GetPath(nTargetRegion,nTargetIdx); 448 aTemplateItem.aRegionName = pViewItem->maHelpText; 449 aTemplateItem.aThumbnail = pViewItem->maPreview1; 450 451 pTarget->maTemplates.push_back(aTemplateItem); 452 453 if (!bCopy) 454 { 455 // remove template from region cached data 456 457 std::vector<TemplateItemProperties>::iterator aIter; 458 for (aIter = pSrc->maTemplates.begin(); aIter != pSrc->maTemplates.end();) 459 { 460 if (aIter->nDocId == pViewItem->mnDocId) 461 { 462 aIter = pSrc->maTemplates.erase(aIter); 463 } 464 else 465 { 466 // Keep region document id synchronized with SfxDocumentTemplates 467 if (aIter->nDocId > pViewItem->mnDocId) 468 --aIter->nDocId; 469 470 ++aIter; 471 } 472 } 473 474 // Keep view document id synchronized with SfxDocumentTemplates 475 for (auto const& item : mItemList) 476 { 477 auto pTemplateViewItem = static_cast<TemplateViewItem*>(item.get()); 478 if (pTemplateViewItem->mnDocId > pViewItem->mnDocId) 479 --pTemplateViewItem->mnDocId; 480 } 481 } 482 483 CalculateItemPositions(); 484 Invalidate(); 485 486 return true; 487 } 488 489 return false; 490 } 491 492 void TemplateLocalView::moveTemplates(const std::set<const ThumbnailViewItem*, selection_cmp_fn> &rItems, 493 const sal_uInt16 nTargetItem) 494 { 495 TemplateContainerItem *pTarget = nullptr; 496 TemplateContainerItem *pSrc = nullptr; 497 498 for (auto const & pRegion : maRegions) 499 { 500 if (pRegion->mnId == nTargetItem) 501 pTarget = pRegion.get(); 502 } 503 504 if (!pTarget) 505 return; 506 507 bool refresh = false; 508 509 sal_uInt16 nTargetRegion = pTarget->mnRegionId; 510 sal_uInt16 nTargetIdx = mpDocTemplates->GetCount(nTargetRegion); // Next Idx 511 std::vector<sal_uInt16> aItemIds; // List of moved items ids (also prevents the invalidation of rItems iterators when we remove them as we go) 512 513 std::set<const ThumbnailViewItem*,selection_cmp_fn>::const_iterator aSelIter; 514 for ( aSelIter = rItems.begin(); aSelIter != rItems.end(); ++aSelIter, ++nTargetIdx ) 515 { 516 const TemplateViewItem *pViewItem = static_cast<const TemplateViewItem*>(*aSelIter); 517 sal_uInt16 nSrcRegionId = pViewItem->mnRegionId; 518 519 for (auto const & pRegion : maRegions) 520 { 521 if (pRegion->mnRegionId == nSrcRegionId) 522 pSrc = pRegion.get(); 523 } 524 525 if(pSrc) 526 { 527 bool bCopy = !mpDocTemplates->Move(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId); 528 529 if (bCopy) 530 { 531 OUString sQuery = SfxResId(STR_MSG_QUERY_COPY).replaceFirst("$1", pViewItem->maTitle).replaceFirst("$2", 532 getRegionName(nTargetRegion)); 533 std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, sQuery)); 534 if (xQueryDlg->run() != RET_YES) 535 { 536 OUString sMsg(SfxResId(STR_MSG_ERROR_LOCAL_MOVE)); 537 sMsg = sMsg.replaceFirst("$1",getRegionName(nTargetRegion)); 538 std::unique_ptr<weld::MessageDialog> xBox(Application::CreateMessageDialog(GetDrawingArea(), 539 VclMessageType::Warning, VclButtonsType::Ok, sMsg.replaceFirst( "$2",pViewItem->maTitle))); 540 xBox->run(); 541 542 return; //return if any single move operation fails 543 } 544 545 if (!mpDocTemplates->Copy(nTargetRegion,nTargetIdx,nSrcRegionId,pViewItem->mnDocId)) 546 { 547 continue; 548 } 549 } 550 551 // move template to destination 552 553 TemplateItemProperties aTemplateItem; 554 aTemplateItem.nId = nTargetIdx + 1; 555 aTemplateItem.nDocId = nTargetIdx; 556 aTemplateItem.nRegionId = nTargetRegion; 557 aTemplateItem.aName = pViewItem->maTitle; 558 aTemplateItem.aPath = mpDocTemplates->GetPath(nTargetRegion,nTargetIdx); 559 aTemplateItem.aRegionName = pViewItem->maHelpText; 560 aTemplateItem.aThumbnail = pViewItem->maPreview1; 561 562 pTarget->maTemplates.push_back(aTemplateItem); 563 564 if (!bCopy) 565 { 566 // remove template from region cached data 567 568 std::vector<TemplateItemProperties>::iterator pPropIter; 569 for (pPropIter = pSrc->maTemplates.begin(); pPropIter != pSrc->maTemplates.end();) 570 { 571 if (pPropIter->nDocId == pViewItem->mnDocId) 572 { 573 pPropIter = pSrc->maTemplates.erase(pPropIter); 574 aItemIds.push_back(pViewItem->mnDocId + 1);//mnid 575 } 576 else 577 { 578 // Keep region document id synchronized with SfxDocumentTemplates 579 if (pPropIter->nDocId > pViewItem->mnDocId) 580 --pPropIter->nDocId; 581 582 ++pPropIter; 583 } 584 } 585 586 // Keep view document id synchronized with SfxDocumentTemplates 587 for (auto const& item : mItemList) 588 { 589 auto pTemplateViewItem = static_cast<TemplateViewItem*>(item.get()); 590 if (pTemplateViewItem->mnDocId > pViewItem->mnDocId) 591 --pTemplateViewItem->mnDocId; 592 } 593 } 594 } 595 596 refresh = true; 597 } 598 599 // Remove items from the current view 600 for (auto const& itemId : aItemIds) 601 RemoveItem(itemId); 602 603 if (refresh) 604 { 605 CalculateItemPositions(); 606 Invalidate(); 607 } 608 } 609 610 bool TemplateLocalView::copyFrom (TemplateContainerItem *pItem, const OUString &rPath) 611 { 612 sal_uInt16 nId = 1; 613 sal_uInt16 nDocId = 0; 614 sal_uInt16 nRegionId = pItem->mnRegionId; 615 OUString aPath(rPath); 616 617 if (!pItem->maTemplates.empty()) 618 { 619 nId = pItem->maTemplates.back().nId+1; 620 nDocId = pItem->maTemplates.back().nDocId+1; 621 } 622 623 if (mpDocTemplates->CopyFrom(nRegionId,nDocId,aPath)) 624 { 625 TemplateItemProperties aTemplate; 626 aTemplate.nId = nId; 627 aTemplate.nDocId = nDocId; 628 aTemplate.nRegionId = nRegionId; 629 aTemplate.aName = aPath; 630 aTemplate.aThumbnail = TemplateLocalView::fetchThumbnail(rPath, 631 TEMPLATE_THUMBNAIL_MAX_WIDTH, 632 TEMPLATE_THUMBNAIL_MAX_HEIGHT); 633 aTemplate.aPath = rPath; 634 aTemplate.aRegionName = getRegionName(nRegionId); 635 636 pItem->maTemplates.push_back(aTemplate); 637 638 CalculateItemPositions(); 639 640 return true; 641 } 642 643 return false; 644 } 645 646 bool TemplateLocalView::exportTo(const sal_uInt16 nItemId, const sal_uInt16 nRegionItemId, const OUString &rName) 647 { 648 for (auto const & pRegItem : maRegions) 649 { 650 if (pRegItem->mnId == nRegionItemId) 651 { 652 for (auto const& elem : pRegItem->maTemplates) 653 { 654 if (elem.nId == nItemId) 655 { 656 return mpDocTemplates->CopyTo(pRegItem->mnRegionId,elem.nDocId,rName); 657 } 658 } 659 660 break; 661 } 662 } 663 664 return false; 665 } 666 667 bool TemplateLocalView::renameItem(ThumbnailViewItem* pItem, const OUString& sNewTitle) 668 { 669 sal_uInt16 nRegionId = 0; 670 sal_uInt16 nDocId = USHRT_MAX; 671 TemplateViewItem* pDocItem = dynamic_cast<TemplateViewItem*>( pItem ); 672 673 if ( pDocItem ) 674 { 675 nRegionId = pDocItem->mnRegionId; 676 nDocId = pDocItem->mnDocId; 677 } 678 679 return mpDocTemplates->SetName( sNewTitle, nRegionId, nDocId ); 680 } 681 682 void TemplateLocalView::insertItems(const std::vector<TemplateItemProperties> &rTemplates, bool isRegionSelected, bool bShowCategoryInTooltip) 683 { 684 std::vector<std::unique_ptr<ThumbnailViewItem>> aItems(rTemplates.size()); 685 for (size_t i = 0, n = rTemplates.size(); i < n; ++i ) 686 { 687 const TemplateItemProperties *pCur = &rTemplates[i]; 688 689 std::unique_ptr<TemplateViewItem> pChild; 690 if(isRegionSelected) 691 pChild.reset(new TemplateViewItem(*this, pCur->nId)); 692 else 693 pChild.reset(new TemplateViewItem(*this, i+1)); 694 695 pChild->mnDocId = pCur->nDocId; 696 pChild->mnRegionId = pCur->nRegionId; 697 pChild->maTitle = pCur->aName; 698 pChild->setPath(pCur->aPath); 699 700 if(!bShowCategoryInTooltip) 701 pChild->setHelpText(pCur->aName); 702 else 703 { 704 OUString sHelpText = SfxResId(STR_TEMPLATE_TOOLTIP); 705 sHelpText = (sHelpText.replaceFirst("$1", pCur->aName)).replaceFirst("$2", pCur->aRegionName); 706 pChild->setHelpText(sHelpText); 707 } 708 709 pChild->maPreview1 = pCur->aThumbnail; 710 711 if(IsDefaultTemplate(pCur->aPath)) 712 pChild->showDefaultIcon(true); 713 714 if ( pCur->aThumbnail.IsEmpty() ) 715 { 716 // Use the default thumbnail if we have nothing else 717 pChild->maPreview1 = TemplateLocalView::getDefaultThumbnail(pCur->aPath); 718 } 719 720 aItems[i] = std::move(pChild); 721 } 722 723 updateItems(std::move(aItems)); 724 } 725 726 bool TemplateLocalView::MouseButtonDown( const MouseEvent& rMEvt ) 727 { 728 GrabFocus(); 729 return ThumbnailView::MouseButtonDown(rMEvt); 730 } 731 732 bool TemplateLocalView::Command(const CommandEvent& rCEvt) 733 { 734 if (rCEvt.GetCommand() != CommandEventId::ContextMenu) 735 return CustomWidgetController::Command(rCEvt); 736 737 if (rCEvt.IsMouseEvent()) 738 { 739 deselectItems(); 740 size_t nPos = ImplGetItem(rCEvt.GetMousePosPixel()); 741 Point aPosition(rCEvt.GetMousePosPixel()); 742 maPosition = aPosition; 743 ThumbnailViewItem* pItem = ImplGetItem(nPos); 744 const TemplateViewItem *pViewItem = dynamic_cast<const TemplateViewItem*>(pItem); 745 746 if(pViewItem) 747 { 748 maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); 749 maCreateContextMenuHdl.Call(pItem); 750 } 751 } 752 else 753 { 754 for (ThumbnailViewItem* pItem : mFilteredItemList) 755 { 756 //create context menu for the first selected item 757 if (pItem->isSelected()) 758 { 759 deselectItems(); 760 pItem->setSelection(true); 761 maItemStateHdl.Call(pItem); 762 tools::Rectangle aRect = pItem->getDrawArea(); 763 maPosition = aRect.Center(); 764 maSelectedItem = dynamic_cast<TemplateViewItem*>(pItem); 765 maCreateContextMenuHdl.Call(pItem); 766 break; 767 } 768 } 769 } 770 return true; 771 } 772 773 bool TemplateLocalView::KeyInput( const KeyEvent& rKEvt ) 774 { 775 vcl::KeyCode aKeyCode = rKEvt.GetKeyCode(); 776 777 if(aKeyCode == ( KEY_MOD1 | KEY_A ) ) 778 { 779 for (ThumbnailViewItem* pItem : mFilteredItemList) 780 { 781 if (!pItem->isSelected()) 782 { 783 pItem->setSelection(true); 784 maItemStateHdl.Call(pItem); 785 } 786 } 787 788 if (IsReallyVisible() && IsUpdateMode()) 789 Invalidate(); 790 return true; 791 } 792 else if( aKeyCode == KEY_DELETE && !mFilteredItemList.empty()) 793 { 794 std::unique_ptr<weld::MessageDialog> xQueryDlg(Application::CreateMessageDialog(GetDrawingArea(), VclMessageType::Question, VclButtonsType::YesNo, 795 SfxResId(STR_QMSG_SEL_TEMPLATE_DELETE))); 796 if (xQueryDlg->run() != RET_YES) 797 return true; 798 799 //copy to avoid changing filtered item list during deletion 800 ThumbnailValueItemList mFilteredItemListCopy = mFilteredItemList; 801 802 for (ThumbnailViewItem* pItem : mFilteredItemListCopy) 803 { 804 if (pItem->isSelected()) 805 { 806 maDeleteTemplateHdl.Call(pItem); 807 } 808 } 809 reload(); 810 } 811 812 return ThumbnailView::KeyInput(rKEvt); 813 } 814 815 void TemplateLocalView::setOpenRegionHdl(const Link<void*,void> &rLink) 816 { 817 maOpenRegionHdl = rLink; 818 } 819 820 void TemplateLocalView::setCreateContextMenuHdl(const Link<ThumbnailViewItem*,void> &rLink) 821 { 822 maCreateContextMenuHdl = rLink; 823 } 824 825 void TemplateLocalView::setOpenTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) 826 { 827 maOpenTemplateHdl = rLink; 828 } 829 830 void TemplateLocalView::setEditTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) 831 { 832 maEditTemplateHdl = rLink; 833 } 834 835 void TemplateLocalView::setDeleteTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) 836 { 837 maDeleteTemplateHdl = rLink; 838 } 839 840 void TemplateLocalView::setDefaultTemplateHdl(const Link<ThumbnailViewItem*,void> &rLink) 841 { 842 maDefaultTemplateHdl = rLink; 843 } 844 845 BitmapEx TemplateLocalView::scaleImg (const BitmapEx &rImg, tools::Long width, tools::Long height) 846 { 847 BitmapEx aImg = rImg; 848 849 if (!rImg.IsEmpty()) 850 { 851 Size aSize = rImg.GetSizePixel(); 852 853 if (aSize.Width() == 0) 854 aSize.setWidth( 1 ); 855 856 if (aSize.Height() == 0) 857 aSize.setHeight( 1 ); 858 859 // make the picture fit the given width/height constraints 860 double nRatio = std::min(double(width)/double(aSize.Width()), double(height)/double(aSize.Height())); 861 862 aImg.Scale(Size(aSize.Width() * nRatio, aSize.Height() * nRatio)); 863 } 864 865 return aImg; 866 } 867 868 bool TemplateLocalView::IsDefaultTemplate(const OUString& rPath) 869 { 870 SvtModuleOptions aModOpt; 871 const css::uno::Sequence<OUString> &aServiceNames = aModOpt.GetAllServiceNames(); 872 873 return std::any_of(aServiceNames.begin(), aServiceNames.end(), [&rPath](const OUString& rName) { 874 return SfxObjectFactory::GetStandardTemplate(rName).match(rPath); }); 875 } 876 877 void TemplateLocalView::RemoveDefaultTemplateIcon(std::u16string_view rPath) 878 { 879 for (const std::unique_ptr<ThumbnailViewItem>& pItem : mItemList) 880 { 881 TemplateViewItem* pViewItem = dynamic_cast<TemplateViewItem*>(pItem.get()); 882 if (pViewItem && pViewItem->getPath().match(rPath)) 883 { 884 pViewItem->showDefaultIcon(false); 885 Invalidate(); 886 return; 887 } 888 } 889 } 890 891 BitmapEx TemplateLocalView::getDefaultThumbnail( const OUString& rPath ) 892 { 893 BitmapEx aImg; 894 INetURLObject aUrl(rPath); 895 OUString aExt = aUrl.getExtension(); 896 897 if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::WRITER, aExt) ) 898 aImg = BitmapEx(SFX_THUMBNAIL_TEXT); 899 else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::CALC, aExt) ) 900 aImg = BitmapEx(SFX_THUMBNAIL_SHEET); 901 else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::IMPRESS, aExt) ) 902 aImg = BitmapEx(SFX_THUMBNAIL_PRESENTATION); 903 else if ( ViewFilter_Application::isFilteredExtension( FILTER_APPLICATION::DRAW, aExt) ) 904 aImg = BitmapEx(SFX_THUMBNAIL_DRAWING); 905 906 return aImg; 907 } 908 909 BitmapEx TemplateLocalView::fetchThumbnail (const OUString &msURL, tools::Long width, tools::Long height) 910 { 911 return TemplateLocalView::scaleImg(ThumbnailView::readThumbnail(msURL), width, height); 912 } 913 914 void TemplateLocalView::OnItemDblClicked (ThumbnailViewItem *pItem) 915 { 916 TemplateViewItem* pViewItem = dynamic_cast<TemplateViewItem*>(pItem); 917 918 if( pViewItem ) 919 maOpenTemplateHdl.Call(pViewItem); 920 } 921 922 923 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 924
