/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * This file incorporates work covered by the following license notice: * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed * with this work for additional information regarding copyright * ownership. The ASF licenses this file to you under the Apache * License, Version 2.0 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; bool SdPageObjsTLV::bIsInDrag = false; bool SdPageObjsTLV::IsInDrag() { return bIsInDrag; } SotClipboardFormatId SdPageObjsTLV::SdPageObjsTransferable::mnListBoxDropFormatId = static_cast(SAL_MAX_UINT32); SdPageObjsTLV::SdPageObjsTransferable::SdPageObjsTransferable( const INetBookmark& rBookmark, ::sd::DrawDocShell& rDocShell, NavigatorDragType eDragType) : SdTransferable(rDocShell.GetDoc(), nullptr, true), maBookmark( rBookmark ), mrDocShell( rDocShell ), meDragType( eDragType ) { } SdPageObjsTLV::SdPageObjsTransferable::~SdPageObjsTransferable() { } void SdPageObjsTLV::SdPageObjsTransferable::AddSupportedFormats() { AddFormat(SotClipboardFormatId::NETSCAPE_BOOKMARK); AddFormat(SotClipboardFormatId::TREELISTBOX); AddFormat(GetListBoxDropFormatId()); } bool SdPageObjsTLV::SdPageObjsTransferable::GetData( const css::datatransfer::DataFlavor& rFlavor, const OUString& /*rDestDoc*/ ) { SotClipboardFormatId nFormatId = SotExchange::GetFormat( rFlavor ); switch (nFormatId) { case SotClipboardFormatId::NETSCAPE_BOOKMARK: SetINetBookmark( maBookmark, rFlavor ); return true; case SotClipboardFormatId::TREELISTBOX: { css::uno::Any aTreeListBoxData; // empty for now SetAny(aTreeListBoxData); return true; } default: return false; } } void SdPageObjsTLV::SdPageObjsTransferable::DragFinished( sal_Int8 nDropAction ) { SdPageObjsTLV::OnDragFinished(); SdTransferable::DragFinished(nDropAction); } sal_Int64 SAL_CALL SdPageObjsTLV::SdPageObjsTransferable::getSomething( const css::uno::Sequence< sal_Int8 >& rId ) { return comphelper::getSomethingImpl(rId, this, comphelper::FallbackToGetSomethingOf{}); } const css::uno::Sequence& SdPageObjsTLV::SdPageObjsTransferable::getUnoTunnelId() { static const comphelper::UnoIdInit theSdPageObjsTLBUnoTunnelId; return theSdPageObjsTLBUnoTunnelId.getSeq(); } SdPageObjsTLV::SdPageObjsTransferable* SdPageObjsTLV::SdPageObjsTransferable::getImplementation( const css::uno::Reference< css::uno::XInterface >& rxData ) noexcept { try { return comphelper::getFromUnoTunnel(rxData); } catch( const css::uno::Exception& ) { } return nullptr; } SotClipboardFormatId SdPageObjsTLV::SdPageObjsTransferable::GetListBoxDropFormatId() { if (mnListBoxDropFormatId == static_cast(SAL_MAX_UINT32)) mnListBoxDropFormatId = SotExchange::RegisterFormatMimeType("application/x-openoffice-treelistbox-moveonly;windows_formatname=\"SV_LBOX_DD_FORMAT_MOVE\""); return mnListBoxDropFormatId; } /** * @return true if children of the specified string are selected */ bool SdPageObjsTLV::HasSelectedChildren( std::u16string_view rName ) { bool bChildren = false; if( !rName.empty() ) { std::unique_ptr xEntry(m_xTreeView->make_iterator()); OUString aTmp; if (m_xTreeView->get_iter_first(*xEntry)) { do { aTmp = m_xTreeView->get_text(*xEntry); if (aTmp == rName) { // see if any of the selected nodes are subchildren of this node m_xTreeView->selected_foreach([this, &bChildren, &xEntry](weld::TreeIter& rEntry){ std::unique_ptr xParent(m_xTreeView->make_iterator(&rEntry)); while (!bChildren && m_xTreeView->iter_parent(*xParent)) bChildren = m_xTreeView->iter_compare(*xParent, *xEntry) == 0; return bChildren; }); break; } } while (m_xTreeView->iter_next(*xEntry)); } } return bChildren; } void SdPageObjsTLV::SetShowAllShapes ( const bool bShowAllShapes, const bool bFillList) { m_bShowAllShapes = bShowAllShapes; if (bFillList) { if (m_pMedium == nullptr) Fill(m_pDoc, m_bShowAllPages, m_aDocName); else Fill(m_pDoc, m_pMedium, m_aDocName); } } bool SdPageObjsTLV::IsEqualToShapeList(std::unique_ptr& rEntry, const SdrObjList& rList, std::u16string_view rListName) { if (!rEntry) return false; OUString aName = m_xTreeView->get_text(*rEntry); if (rListName != aName) return false; if (!m_xTreeView->iter_next(*rEntry)) rEntry.reset(); SdrObjListIter aIter(&rList, !rList.HasObjectNavigationOrder() /* use navigation order, if available */, SdrIterMode::Flat); while (aIter.IsMore()) { SdrObject* pObj = aIter.Next(); const OUString aObjectName(GetObjectName(pObj)); if (!aObjectName.isEmpty()) { if (!rEntry) return false; aName = m_xTreeView->get_text(*rEntry); if (aObjectName != aName) return false; if (pObj->IsGroupObject()) { bool bRet = IsEqualToShapeList(rEntry, *pObj->GetSubList(), aObjectName); if (!bRet) return false; } else { if (!m_xTreeView->iter_next(*rEntry)) rEntry.reset(); } } } return true; } /** * Checks if the pages (PageKind::Standard) of a doc and the objects on the pages * are identical to the TreeLB. * If a doc is provided, this will be the used doc (important by more than * one document). */ bool SdPageObjsTLV::IsEqualToDoc( const SdDrawDocument* pInDoc ) { if( pInDoc ) m_pDoc = pInDoc; if( !m_pDoc ) return false; std::unique_ptr xEntry(m_xTreeView->make_iterator()); if (!m_xTreeView->get_iter_first(*xEntry)) xEntry.reset(); // compare all pages including the objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = m_pDoc->GetPageCount(); while( nPage < nMaxPages ) { const SdPage* pPage = static_cast( m_pDoc->GetPage( nPage ) ); if( pPage->GetPageKind() == PageKind::Standard ) { bool bRet = IsEqualToShapeList(xEntry, *pPage, pPage->GetName()); if (!bRet) return false; } nPage++; } // If there are still entries in the listbox, // then objects (with names) or pages were deleted return !xEntry; } IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, rKEvt, bool) { const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); if (m_xAccel->execute(rKeyCode)) { // the accelerator consumed the event return true; } if (rKeyCode.GetCode() == KEY_RETURN) { std::unique_ptr xCursor(m_xTreeView->make_iterator()); if (m_xTreeView->get_cursor(xCursor.get()) && m_xTreeView->iter_has_child(*xCursor)) { if (m_xTreeView->get_row_expanded(*xCursor)) m_xTreeView->collapse_row(*xCursor); else m_xTreeView->expand_row(*xCursor); } m_aRowActivatedHdl.Call(*m_xTreeView); return true; } return m_aKeyPressHdl.Call(rKEvt); } IMPL_LINK(SdPageObjsTLV, MousePressHdl, const MouseEvent&, rMEvt, bool) { m_bSelectionHandlerNavigates = rMEvt.GetClicks() == 1; m_bNavigationGrabsFocus = rMEvt.GetClicks() != 1; return false; } IMPL_LINK_NOARG(SdPageObjsTLV, MouseReleaseHdl, const MouseEvent&, bool) { m_bSelectionHandlerNavigates = false; m_bNavigationGrabsFocus = true; return false; } IMPL_LINK(SdPageObjsTLV, DragBeginHdl, bool&, rUnsetDragIcon, bool) { rUnsetDragIcon = false; return StartDrag(); } namespace { bool CanDragSource(const weld::TreeView& rTreeView) { std::unique_ptr xSource(rTreeView.make_iterator()); if (!rTreeView.get_selected(xSource.get())) return false; std::unique_ptr xSourceParent(rTreeView.make_iterator(xSource.get())); bool bSourceHasParent = rTreeView.iter_parent(*xSourceParent); // level 1 objects only if (!bSourceHasParent || rTreeView.get_iter_depth(*xSourceParent)) return false; SdrObject* pSourceObject = weld::fromId(rTreeView.get_id(*xSource)); if (pSourceObject == reinterpret_cast(1)) pSourceObject = nullptr; if (!pSourceObject) return false; SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject(); if (!pObjectList) return false; return true; } } /** * StartDrag-Request */ bool SdPageObjsTLV::StartDrag() { return !CanDragSource(*m_xTreeView) || DoDrag(); } /** * Begin drag */ bool SdPageObjsTLV::DoDrag() { if (!m_pNavigator) return true; if (!m_xHelper) return true; // Get the view. ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh(); ::sd::ViewShell* pViewShell = GetViewShellForDocShell(*pDocShell); if (pViewShell == nullptr) { OSL_ASSERT(pViewShell!=nullptr); return true; } sd::View* pView = pViewShell->GetView(); if (pView == nullptr) { OSL_ASSERT(pView!=nullptr); return true; } bIsInDrag = true; std::unique_ptr xEntry = m_xTreeView->make_iterator(); bool bUserData = m_xTreeView->get_cursor(xEntry.get()); SdrObject* pObject = nullptr; sal_Int64 nUserData = bUserData ? m_xTreeView->get_id(*xEntry).toInt64() : 0; if (nUserData != 1) pObject = reinterpret_cast(nUserData); if (pObject != nullptr) { // For shapes without a user supplied name (the automatically // created name does not count), a different drag and drop technique // is used. if (GetObjectName(pObject, false).isEmpty()) { AddShapeToTransferable(*m_xHelper, *pObject); m_xHelper->SetView(pView); SD_MOD()->pTransferDrag = m_xHelper.get(); } // Unnamed shapes have to be selected to be recognized by the // current drop implementation. In order to have a consistent // behaviour for all shapes, every shape that is to be dragged is // selected first. SdrPageView* pPageView = pView->GetSdrPageView(); pView->UnmarkAllObj(pPageView); pView->MarkObj(pObject, pPageView); } else { m_xHelper->SetView(pView); SD_MOD()->pTransferDrag = m_xHelper.get(); } return false; } void SdPageObjsTLV::OnDragFinished() { bIsInDrag = false; } SdPageObjsTLVDropTarget::SdPageObjsTLVDropTarget(weld::TreeView& rTreeView) : DropTargetHelper(rTreeView.get_drop_target()) , m_rTreeView(rTreeView) { } /** * AcceptDrop-Event */ sal_Int8 SdPageObjsTLVDropTarget::AcceptDrop(const AcceptDropEvent& rEvt) { weld::TreeView* pSource = m_rTreeView.get_drag_source(); // only dragging within the same widget allowed if (!pSource || pSource != &m_rTreeView) return DND_ACTION_NONE; std::unique_ptr xTarget(m_rTreeView.make_iterator()); if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true)) return DND_ACTION_NONE; std::unique_ptr xSource(m_rTreeView.make_iterator()); if (!m_rTreeView.get_selected(xSource.get())) return DND_ACTION_NONE; std::unique_ptr xTargetParent(m_rTreeView.make_iterator(xTarget.get())); while (m_rTreeView.get_iter_depth(*xTargetParent)) m_rTreeView.iter_parent(*xTargetParent); std::unique_ptr xSourceParent(m_rTreeView.make_iterator(xSource.get())); while (m_rTreeView.get_iter_depth(*xSourceParent)) m_rTreeView.iter_parent(*xSourceParent); // can only drop within the same page if (m_rTreeView.iter_compare(*xTargetParent, *xSourceParent) != 0) return DND_ACTION_NONE; return DND_ACTION_MOVE; } /** * ExecuteDrop-Event */ sal_Int8 SdPageObjsTLVDropTarget::ExecuteDrop( const ExecuteDropEvent& rEvt ) { weld::TreeView* pSource = m_rTreeView.get_drag_source(); // only dragging within the same widget allowed if (!pSource || pSource != &m_rTreeView) return DND_ACTION_NONE; std::unique_ptr xSource(m_rTreeView.make_iterator()); if (!m_rTreeView.get_selected(xSource.get())) return DND_ACTION_NONE; std::unique_ptr xTarget(m_rTreeView.make_iterator()); if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true)) return DND_ACTION_NONE; int nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget) + 1; SdrObject* pTargetObject = weld::fromId(m_rTreeView.get_id(*xTarget)); SdrObject* pSourceObject = weld::fromId(m_rTreeView.get_id(*xSource)); if (pSourceObject == reinterpret_cast(1)) pSourceObject = nullptr; if (pTargetObject != nullptr && pSourceObject != nullptr) { SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject(); if (pObjectList != nullptr) { sal_uInt32 nNewPosition; if (pTargetObject == reinterpret_cast(1)) { nNewPosition = 0; nTargetPos = 0; } else nNewPosition = pTargetObject->GetNavigationPosition() + 1; pObjectList->SetObjectNavigationPosition(*pSourceObject, nNewPosition); } std::unique_ptr xSourceParent(m_rTreeView.make_iterator(xSource.get())); m_rTreeView.iter_parent(*xSourceParent); m_rTreeView.move_subtree(*xSource, xSourceParent.get(), nTargetPos); } return DND_ACTION_NONE; } void SdPageObjsTLV::AddShapeToTransferable ( SdTransferable& rTransferable, const SdrObject& rObject) const { std::unique_ptr pObjectDescriptor(new TransferableObjectDescriptor); bool bIsDescriptorFillingPending (true); const SdrOle2Obj* pOleObject = dynamic_cast(&rObject); if (pOleObject != nullptr && pOleObject->GetObjRef().is()) { // If object has no persistence it must be copied as part of the document try { uno::Reference< embed::XEmbedPersist > xPersObj (pOleObject->GetObjRef(), uno::UNO_QUERY ); if (xPersObj.is() && xPersObj->hasEntry()) { SvEmbedTransferHelper::FillTransferableObjectDescriptor( *pObjectDescriptor, pOleObject->GetObjRef(), pOleObject->GetGraphic(), pOleObject->GetAspect()); bIsDescriptorFillingPending = false; } } catch( uno::Exception& ) { } } ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh(); if (bIsDescriptorFillingPending && pDocShell!=nullptr) { pDocShell->FillTransferableObjectDescriptor(*pObjectDescriptor); } Point aDragPos (rObject.GetCurrentBoundRect().Center()); pObjectDescriptor->maDragStartPos = aDragPos; if (pDocShell != nullptr) pObjectDescriptor->maDisplayName = pDocShell->GetMedium()->GetURLObject().GetURLNoPass(); else pObjectDescriptor->maDisplayName.clear(); rTransferable.SetStartPos(aDragPos); rTransferable.SetObjectDescriptor( std::move(pObjectDescriptor) ); } ::sd::ViewShell* SdPageObjsTLV::GetViewShellForDocShell (::sd::DrawDocShell& rDocShell) { { ::sd::ViewShell* pViewShell = rDocShell.GetViewShell(); if (pViewShell != nullptr) return pViewShell; } try { // Get a component enumeration from the desktop and search it for documents. uno::Reference xContext( ::comphelper::getProcessComponentContext()); uno::Reference xDesktop = frame::Desktop::create(xContext); if ( ! xDesktop.is()) return nullptr; uno::Reference xFrameAccess = xDesktop->getFrames(); if ( ! xFrameAccess.is()) return nullptr; for (sal_Int32 nIndex=0,nCount=xFrameAccess->getCount(); nIndex xFrame; if ( ! (xFrameAccess->getByIndex(nIndex) >>= xFrame)) continue; auto xController = xFrame->getController(); ::sd::DrawController* pController = dynamic_cast(xController.get()); if (pController == nullptr) continue; ::sd::ViewShellBase* pBase = pController->GetViewShellBase(); if (pBase == nullptr) continue; if (pBase->GetDocShell() != &rDocShell) continue; const std::shared_ptr pViewShell (pBase->GetMainViewShell()); if (pViewShell) return pViewShell.get(); } } catch (uno::Exception &) { // When there is an exception then simply use the default value of // bIsEnabled and disable the controls. } return nullptr; } SdPageObjsTLV::SdPageObjsTLV(std::unique_ptr xTreeView) : m_xTreeView(std::move(xTreeView)) , m_xScratchIter(m_xTreeView->make_iterator()) , m_xDropTargetHelper(new SdPageObjsTLVDropTarget(*m_xTreeView)) , m_xAccel(::svt::AcceleratorExecute::createAcceleratorHelper()) , m_pNavigator(nullptr) , m_pDoc(nullptr) , m_pBookmarkDoc(nullptr) , m_pMedium(nullptr) , m_pOwnMedium(nullptr) , m_bLinkableSelected(false) , m_bShowAllShapes(false) , m_bShowAllPages(false) , m_bSelectionHandlerNavigates(false) , m_bNavigationGrabsFocus(true) , m_eSelectionMode(SelectionMode::Single) , m_nSelectEventId(nullptr) , m_nRowActivateEventId(nullptr) { m_xTreeView->connect_expanding(LINK(this, SdPageObjsTLV, RequestingChildrenHdl)); m_xTreeView->connect_changed(LINK(this, SdPageObjsTLV, SelectHdl)); m_xTreeView->connect_row_activated(LINK(this, SdPageObjsTLV, RowActivatedHdl)); m_xTreeView->connect_drag_begin(LINK(this, SdPageObjsTLV, DragBeginHdl)); m_xTreeView->connect_key_press(LINK(this, SdPageObjsTLV, KeyInputHdl)); m_xTreeView->connect_mouse_press(LINK(this, SdPageObjsTLV, MousePressHdl)); m_xTreeView->connect_mouse_release(LINK(this, SdPageObjsTLV, MouseReleaseHdl)); m_xTreeView->set_size_request(m_xTreeView->get_approximate_digit_width() * 28, m_xTreeView->get_text_height() * 8); } IMPL_LINK_NOARG(SdPageObjsTLV, SelectHdl, weld::TreeView&, void) { if (m_nSelectEventId) Application::RemoveUserEvent(m_nSelectEventId); // post the event to process select event after mouse press event m_nSelectEventId = Application::PostUserEvent(LINK(this, SdPageObjsTLV, AsyncSelectHdl)); } IMPL_LINK_NOARG(SdPageObjsTLV, RowActivatedHdl, weld::TreeView&, bool) { if (m_nRowActivateEventId) Application::RemoveUserEvent(m_nRowActivateEventId); // post the event to process row activate after mouse press event m_nRowActivateEventId = Application::PostUserEvent(LINK(this, SdPageObjsTLV, AsyncRowActivatedHdl)); return true; } IMPL_LINK_NOARG(SdPageObjsTLV, AsyncSelectHdl, void*, void) { Select(); } void SdPageObjsTLV::Select() { m_nSelectEventId = nullptr; m_bLinkableSelected = true; m_xTreeView->selected_foreach([this](weld::TreeIter& rEntry){ if (m_xTreeView->get_id(rEntry).toInt64() == 0) m_bLinkableSelected = false; return false; }); m_aChangeHdl.Call(*m_xTreeView); if (m_bSelectionHandlerNavigates) { // Page items in the tree are given user data value 1. // Drawing object items are given user data value of the object pointer they represent. sal_Int64 nUserData = m_xTreeView->get_selected_id().toInt64(); if (nUserData != 1) { SdrObject* pObject = reinterpret_cast(nUserData); if (pObject && pObject->GetName().isEmpty()) { const bool bUndo = pObject->getSdrModelFromSdrObject().IsUndoEnabled(); pObject->getSdrModelFromSdrObject().EnableUndo(false); pObject->SetName(m_xTreeView->get_selected_text(), false); pObject->getSdrModelFromSdrObject().EnableUndo(bUndo); m_aRowActivatedHdl.Call(*m_xTreeView); pObject->getSdrModelFromSdrObject().EnableUndo(false); pObject->SetName(OUString(), false); pObject->getSdrModelFromSdrObject().EnableUndo(bUndo); } else m_aRowActivatedHdl.Call(*m_xTreeView); } else m_aRowActivatedHdl.Call(*m_xTreeView); } if (!m_pNavigator) { m_xHelper.clear(); return; } ::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh(); OUString aURL = INetURLObject(pDocShell->GetMedium()->GetPhysicalName(), INetProtocol::File).GetMainURL(INetURLObject::DecodeMechanism::NONE); NavigatorDragType eDragType = m_pNavigator->GetNavigatorDragType(); OUString sSelectedEntry = m_xTreeView->get_selected_text(); aURL += "#" + sSelectedEntry; INetBookmark aBookmark(aURL, sSelectedEntry); sal_Int8 nDNDActions = DND_ACTION_COPYMOVE; if( eDragType == NAVIGATOR_DRAGTYPE_LINK ) nDNDActions = DND_ACTION_LINK; // Either COPY *or* LINK, never both! else if (m_pDoc->GetSdPageCount(PageKind::Standard) == 1) { // Can not move away the last slide in a document. nDNDActions = DND_ACTION_COPY; } // object is destroyed by internal reference mechanism m_xHelper.set(new SdPageObjsTLV::SdPageObjsTransferable(aBookmark, *pDocShell, eDragType)); rtl::Reference xHelper(m_xHelper); m_xTreeView->enable_drag_source(xHelper, nDNDActions); } IMPL_LINK_NOARG(SdPageObjsTLV, AsyncRowActivatedHdl, void*, void) { m_nRowActivateEventId = nullptr; m_aRowActivatedHdl.Call(*m_xTreeView); } OUString SdPageObjsTLV::GetObjectName( const SdrObject* pObject, const bool bCreate) const { OUString aRet; if ( pObject ) { aRet = pObject->GetName(); if (aRet.isEmpty()) if (auto pOleObj = dynamic_cast(pObject)) aRet = pOleObj->GetPersistName(); } if (bCreate && m_bShowAllShapes && aRet.isEmpty() && pObject!=nullptr) { aRet = SdResId(STR_NAVIGATOR_SHAPE_BASE_NAME) + " (" + pObject->TakeObjNameSingul() +")"; aRet = aRet.replaceFirst("%1", OUString::number(pObject->GetOrdNum() + 1)); } return aRet; } std::vector SdPageObjsTLV::GetSelectEntryList(const int nDepth) const { std::vector aEntries; m_xTreeView->selected_foreach([this, nDepth, &aEntries](weld::TreeIter& rEntry){ int nListDepth = m_xTreeView->get_iter_depth(rEntry); if (nListDepth == nDepth) aEntries.push_back(m_xTreeView->get_text(rEntry)); return false; }); return aEntries; } /** * Checks if it is a draw file and opens the BookmarkDoc depending of * the provided Docs */ SdDrawDocument* SdPageObjsTLV::GetBookmarkDoc(SfxMedium* pMed) { if ( !m_pBookmarkDoc || (pMed && (!m_pOwnMedium || m_pOwnMedium->GetName() != pMed->GetName())) ) { // create a new BookmarkDoc if now one exists or if a new Medium is provided if (m_pOwnMedium != pMed) { CloseBookmarkDoc(); } if (pMed) { // it looks that it is undefined if a Medium was set by Fill() already DBG_ASSERT( !m_pMedium, "SfxMedium confusion!" ); delete m_pMedium; m_pMedium = nullptr; // take over this Medium (currently used only be Navigator) m_pOwnMedium = pMed; } DBG_ASSERT( m_pMedium || pMed, "No SfxMedium provided!" ); if( pMed ) { // in this mode the document is also owned and controlled by this instance m_xBookmarkDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::STANDARD, true, DocumentType::Impress); if (m_xBookmarkDocShRef->DoLoad(pMed)) m_pBookmarkDoc = m_xBookmarkDocShRef->GetDoc(); else m_pBookmarkDoc = nullptr; } else if ( m_pMedium ) // in this mode the document is owned and controlled by the SdDrawDocument // it can be released by calling the corresponding CloseBookmarkDoc method // successful creation of a document makes this the owner of the medium m_pBookmarkDoc = const_cast(m_pDoc)->OpenBookmarkDoc(m_pMedium); if ( !m_pBookmarkDoc ) { std::unique_ptr xErrorBox(Application::CreateMessageDialog(m_xTreeView.get(), VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR))); xErrorBox->run(); m_pMedium = nullptr; //On failure the SfxMedium is invalid } } return m_pBookmarkDoc; } /** * Entries are inserted only by request (double click) */ IMPL_LINK(SdPageObjsTLV, RequestingChildrenHdl, const weld::TreeIter&, rFileEntry, bool) { if (!m_xTreeView->iter_has_child(rFileEntry)) { if (GetBookmarkDoc()) { SdrObject* pObj = nullptr; OUString sImgPage(BMP_PAGE); OUString sImgPageObjs(BMP_PAGEOBJS); OUString sImgObjects(BMP_OBJECTS); OUString sImgOle(BMP_OLE); OUString sImgGraphic(BMP_GRAPHIC); // document name already inserted // only insert all "normal" ? slides with objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = m_pBookmarkDoc->GetPageCount(); std::unique_ptr xPageEntry; while (nPage < nMaxPages) { SdPage* pPage = static_cast(m_pBookmarkDoc->GetPage(nPage)); if (pPage->GetPageKind() == PageKind::Standard) { OUString sId(OUString::number(1)); m_xTreeView->insert(&rFileEntry, -1, &pPage->GetName(), &sId, nullptr, nullptr, false, m_xScratchIter.get()); m_xTreeView->set_image(*m_xScratchIter, sImgPage); if (!xPageEntry) { xPageEntry = m_xTreeView->make_iterator(&rFileEntry); (void)m_xTreeView->iter_children(*xPageEntry); } else (void)m_xTreeView->iter_next_sibling(*xPageEntry); SdrObjListIter aIter( pPage, SdrIterMode::DeepWithGroups ); while( aIter.IsMore() ) { pObj = aIter.Next(); OUString aStr( GetObjectName( pObj ) ); if( !aStr.isEmpty() ) { if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::OLE2 ) { m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); m_xTreeView->set_image(*m_xScratchIter, sImgOle); } else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic ) { m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); m_xTreeView->set_image(*m_xScratchIter, sImgGraphic); } else { m_xTreeView->insert(xPageEntry.get(), -1, &aStr, nullptr, nullptr, nullptr, false, m_xScratchIter.get()); m_xTreeView->set_image(*m_xScratchIter, sImgObjects); } } } if (m_xTreeView->iter_has_child(*xPageEntry)) { m_xTreeView->set_image(*xPageEntry, sImgPageObjs); } } nPage++; } } } return true; } void SdPageObjsTLV::SetSdNavigator(SdNavigatorWin* pNavigator) { m_pNavigator = pNavigator; } void SdPageObjsTLV::SetViewFrame(const SfxViewFrame* pViewFrame) { sd::ViewShellBase* pBase = sd::ViewShellBase::GetViewShellBase(pViewFrame); std::shared_ptr xViewShell = pBase->GetMainViewShell(); SAL_WARN_IF(!xViewShell, "sd", "null pBaseViewFrame"); const css::uno::Reference< css::frame::XFrame > xFrame = xViewShell ? xViewShell->GetViewFrame()->GetFrame().GetFrameInterface() : nullptr; m_xAccel->init(::comphelper::getProcessComponentContext(), xFrame); } /** * Close and delete bookmark document */ void SdPageObjsTLV::CloseBookmarkDoc() { if (m_xBookmarkDocShRef.is()) { m_xBookmarkDocShRef->DoClose(); m_xBookmarkDocShRef.clear(); // Medium is owned by document, so it's destroyed already m_pOwnMedium = nullptr; } else if (m_pBookmarkDoc) { DBG_ASSERT(!m_pOwnMedium, "SfxMedium confusion!"); if (m_pDoc) { // The document owns the Medium, so the Medium will be invalid after closing the document const_cast(m_pDoc)->CloseBookmarkDoc(); m_pMedium = nullptr; } } else { // perhaps mpOwnMedium provided, but no successful creation of BookmarkDoc delete m_pOwnMedium; m_pOwnMedium = nullptr; } m_pBookmarkDoc = nullptr; } bool SdPageObjsTLV::PageBelongsToCurrentShow(const SdPage* pPage) const { // Return as default when there is no custom show or when none // is used. The page does then belong to the standard show. bool bBelongsToShow = true; if (m_pDoc->getPresentationSettings().mbCustomShow) { // Get the current custom show. SdCustomShow* pCustomShow = nullptr; SdCustomShowList* pShowList = const_cast(m_pDoc)->GetCustomShowList(); if (pShowList != nullptr) { sal_uLong nCurrentShowIndex = pShowList->GetCurPos(); pCustomShow = (*pShowList)[nCurrentShowIndex].get(); } // Check whether the given page is part of that custom show. if (pCustomShow != nullptr) { bBelongsToShow = false; size_t nPageCount = pCustomShow->PagesVector().size(); for (size_t i=0; iPagesVector()[i]) bBelongsToShow = true; } } return bBelongsToShow; } void SdPageObjsTLV::AddShapeList ( const SdrObjList& rList, const SdrObject* pShape, const OUString& rsName, const bool bIsExcluded, const weld::TreeIter* pParentEntry) { OUString aIcon(BMP_PAGE); if (bIsExcluded) aIcon = BMP_PAGE_EXCLUDED; else if (pShape != nullptr) aIcon = BMP_GROUP; OUString aUserData("1"); if (pShape != nullptr) aUserData = weld::toId(pShape); std::unique_ptr xEntry = m_xTreeView->make_iterator(); InsertEntry(pParentEntry, aUserData, rsName, aIcon, xEntry.get()); SdrObjListIter aIter( &rList, !rList.HasObjectNavigationOrder() /* use navigation order, if available */, SdrIterMode::Flat); while( aIter.IsMore() ) { SdrObject* pObj = aIter.Next(); OSL_ASSERT(pObj!=nullptr); // Get the shape name. OUString aStr (GetObjectName( pObj ) ); OUString sId(weld::toId(pObj)); if( !aStr.isEmpty() ) { if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::OLE2 ) { InsertEntry(xEntry.get(), sId, aStr, BMP_OLE); } else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == SdrObjKind::Graphic ) { InsertEntry(xEntry.get(), sId, aStr, BMP_GRAPHIC); } else if (pObj->IsGroupObject()) { AddShapeList( *pObj->GetSubList(), pObj, aStr, false, xEntry.get()); } else { InsertEntry(xEntry.get(), sId, aStr, BMP_OBJECTS); } } } if (!m_xTreeView->iter_has_child(*xEntry)) return; if (bIsExcluded) m_xTreeView->set_image(*xEntry, BMP_PAGEOBJS_EXCLUDED); else m_xTreeView->set_image(*xEntry, BMP_PAGEOBJS); m_xTreeView->expand_row(*xEntry); } /** * Fill TreeLB with pages and objects */ void SdPageObjsTLV::Fill(const SdDrawDocument* pInDoc, bool bAllPages, const OUString& rDocName) { OUString aSelection = m_xTreeView->get_selected_text(); clear(); m_pDoc = pInDoc; m_aDocName = rDocName; m_bShowAllPages = bAllPages; m_pMedium = nullptr; // first insert all pages including objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = m_pDoc->GetPageCount(); while( nPage < nMaxPages ) { const SdPage* pPage = static_cast( m_pDoc->GetPage( nPage ) ); if( (m_bShowAllPages || pPage->GetPageKind() == PageKind::Standard) && (pPage->GetPageKind() != PageKind::Handout) ) //#94954# never list the normal handout page ( handout-masterpage is used instead ) { bool bPageExcluded = pPage->IsExcluded(); bool bPageBelongsToShow = PageBelongsToCurrentShow (pPage); bPageExcluded |= !bPageBelongsToShow; AddShapeList(*pPage, nullptr, pPage->GetName(), bPageExcluded, nullptr); } nPage++; } // then insert all master pages including objects if( m_bShowAllPages ) { nPage = 0; const sal_uInt16 nMaxMasterPages = m_pDoc->GetMasterPageCount(); while( nPage < nMaxMasterPages ) { const SdPage* pPage = static_cast( m_pDoc->GetMasterPage( nPage ) ); AddShapeList(*pPage, nullptr, pPage->GetName(), false, nullptr); nPage++; } } if (!aSelection.isEmpty()) { m_xTreeView->all_foreach([this, &aSelection](weld::TreeIter& rEntry){ if (m_xTreeView->get_text(rEntry) == aSelection) { m_xTreeView->select(rEntry); return true; } return false; }); } } /** * We insert only the first entry. Children are created on demand. */ void SdPageObjsTLV::Fill( const SdDrawDocument* pInDoc, SfxMedium* pInMedium, const OUString& rDocName ) { m_pDoc = pInDoc; // this object now owns the Medium m_pMedium = pInMedium; m_aDocName = rDocName; OUString sId(OUString::number(1)); // insert document name m_xTreeView->insert(nullptr, -1, &m_aDocName, &sId, nullptr, nullptr, true, m_xScratchIter.get()); m_xTreeView->set_image(*m_xScratchIter, BMP_DOC_OPEN); } /** * select an entry in TreeLB */ bool SdPageObjsTLV::SelectEntry( std::u16string_view rName ) { bool bFound = false; if (!rName.empty()) { std::unique_ptr xEntry(m_xTreeView->make_iterator()); OUString aTmp; if (m_xTreeView->get_iter_first(*xEntry)) { do { aTmp = m_xTreeView->get_text(*xEntry); if (aTmp == rName) { m_xTreeView->set_cursor(*xEntry); m_xTreeView->select(*xEntry); bFound = true; break; } } while (m_xTreeView->iter_next(*xEntry)); } } return bFound; } SdPageObjsTLV::~SdPageObjsTLV() { if (m_nSelectEventId) Application::RemoveUserEvent(m_nSelectEventId); if (m_nRowActivateEventId) Application::RemoveUserEvent(m_nRowActivateEventId); if (m_pBookmarkDoc) CloseBookmarkDoc(); else { // no document was created from m_pMedium, so this object is still the owner of it delete m_pMedium; } m_xAccel.reset(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */