/* -*- 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 #include #include #include #include #include #include #include #include #include #include using namespace com::sun::star; class SdPageObjsTLB::IconProvider { public: IconProvider(); // Regular icons. Image const maImgPage; Image const maImgPageExcl; Image const maImgPageObjsExcl; Image const maImgPageObjs; Image const maImgObjects; Image const maImgGroup; }; bool SdPageObjsTLB::bIsInDrag = false; bool SdPageObjsTLB::IsInDrag() { return bIsInDrag; } SotClipboardFormatId SdPageObjsTLB::SdPageObjsTransferable::mnListBoxDropFormatId = static_cast(SAL_MAX_UINT32); SdPageObjsTLB::SdPageObjsTransferable::SdPageObjsTransferable( SdPageObjsTLB& rParent, const INetBookmark& rBookmark, ::sd::DrawDocShell& rDocShell, NavigatorDragType eDragType) : SdTransferable(rDocShell.GetDoc(), nullptr, true), mrParent( rParent ), maBookmark( rBookmark ), mrDocShell( rDocShell ), meDragType( eDragType ) { rParent.SetupDragOrigin(); } VCL_BUILDER_FACTORY_CONSTRUCTOR(SdPageObjsTLB, WB_TABSTOP) SdPageObjsTLB::SdPageObjsTransferable::~SdPageObjsTransferable() { } void SdPageObjsTLB::SdPageObjsTransferable::AddSupportedFormats() { AddFormat(SotClipboardFormatId::NETSCAPE_BOOKMARK); AddFormat(SotClipboardFormatId::TREELISTBOX); AddFormat(GetListBoxDropFormatId()); } bool SdPageObjsTLB::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 SdPageObjsTLB::SdPageObjsTransferable::DragFinished( sal_Int8 nDropAction ) { mrParent.OnDragFinished(); SdTransferable::DragFinished(nDropAction); } sal_Int64 SAL_CALL SdPageObjsTLB::SdPageObjsTransferable::getSomething( const css::uno::Sequence< sal_Int8 >& rId ) { sal_Int64 nRet; if( ( rId.getLength() == 16 ) && ( 0 == memcmp( getUnoTunnelId().getConstArray(), rId.getConstArray(), 16 ) ) ) { nRet = static_cast(reinterpret_cast(this)); } else nRet = SdTransferable::getSomething(rId); return nRet; } namespace { class theSdPageObjsTLBUnoTunnelId : public rtl::Static< UnoTunnelIdInit, theSdPageObjsTLBUnoTunnelId > {}; } const css::uno::Sequence< sal_Int8 >& SdPageObjsTLB::SdPageObjsTransferable::getUnoTunnelId() { return theSdPageObjsTLBUnoTunnelId::get().getSeq(); } SdPageObjsTLB::SdPageObjsTransferable* SdPageObjsTLB::SdPageObjsTransferable::getImplementation( const css::uno::Reference< css::uno::XInterface >& rxData ) throw() { try { css::uno::Reference< css::lang::XUnoTunnel > xUnoTunnel( rxData, css::uno::UNO_QUERY_THROW ); return reinterpret_cast( sal::static_int_cast( xUnoTunnel->getSomething( SdPageObjsTLB::SdPageObjsTransferable::getUnoTunnelId()) ) ); } catch( const css::uno::Exception& ) { } return nullptr; } SotClipboardFormatId SdPageObjsTLB::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; } SdPageObjsTLB::SdPageObjsTLB( vcl::Window* pParentWin, WinBits nStyle ) : SvTreeListBox ( pParentWin, nStyle ) , mpDoc ( nullptr ) , mpBookmarkDoc ( nullptr ) , mpMedium ( nullptr ) , mpOwnMedium ( nullptr ) , maImgOle ( StockImage::Yes, BMP_OLE ) , maImgGraphic ( StockImage::Yes, BMP_GRAPHIC ) , mbLinkableSelected ( false ) , mbSaveTreeItemState ( false ) , mbShowAllShapes ( false ) , mbShowAllPages ( false ) , mbSelectionHandlerNavigates(false) , mbNavigationGrabsFocus(true) { // add lines to Tree-ListBox SetStyle( GetStyle() | WB_TABSTOP | WB_BORDER | WB_HASLINES | WB_HASBUTTONS | // WB_HASLINESATROOT | WB_HSCROLL | WB_HASBUTTONSATROOT ); SetQuickSearch(true); /* i31275 */; SetNodeBitmaps(Image(StockImage::Yes, BMP_EXPAND), Image(StockImage::Yes, BMP_COLLAPSE)); SetDragDropMode( DragDropMode::CTRL_MOVE | DragDropMode::CTRL_COPY | DragDropMode::APP_MOVE | DragDropMode::APP_COPY | DragDropMode::APP_DROP ); m_pAccel = ::svt::AcceleratorExecute::createAcceleratorHelper(); } void SdPageObjsTLB::SetSdNavigator(SdNavigatorWin* pNavigator) { mpNavigator = pNavigator; } void SdPageObjsTLB::SetViewFrame( SfxViewFrame* pViewFrame ) { sd::ViewShellBase* pBase = sd::ViewShellBase::GetViewShellBase(pViewFrame); const css::uno::Reference< css::frame::XFrame > xFrame = pBase->GetMainViewShell()->GetViewFrame()->GetFrame().GetFrameInterface(); m_pAccel->init(::comphelper::getProcessComponentContext(), xFrame); } SdPageObjsTLB::~SdPageObjsTLB() { disposeOnce(); } void SdPageObjsTLB::dispose() { if ( mpBookmarkDoc ) CloseBookmarkDoc(); else // no document was created from mpMedium, so this object is still the owner of it delete mpMedium; mpNavigator.clear(); m_pAccel.reset(); SvTreeListBox::dispose(); } // helper function for GetEntryAltText and GetEntryLongDescription OUString SdPageObjsTLB::getAltLongDescText(SvTreeListEntry* pEntry , bool isAltText) const { sal_uInt16 maxPages = mpDoc->GetPageCount(); sal_uInt16 pageNo; SdrObject* pObj = nullptr; OUString ParentName = GetEntryText( GetRootLevelParent( pEntry ) ); for( pageNo = 0; pageNo < maxPages; pageNo++ ) { const SdPage* pPage = static_cast( mpDoc->GetPage( pageNo ) ); if( pPage->GetPageKind() != PageKind::Standard ) continue; if( pPage->GetName() != ParentName ) continue; SdrObjListIter aIter( pPage, SdrIterMode::Flat ); while( aIter.IsMore() ) { pObj = aIter.Next(); if( GetEntryText(pEntry) == GetObjectName( pObj ) ) { if( isAltText ) return pObj->GetTitle(); else return pObj->GetDescription(); } } } return OUString(); } OUString SdPageObjsTLB::GetEntryAltText( SvTreeListEntry* pEntry ) const { return getAltLongDescText( pEntry, true ); } OUString SdPageObjsTLB::GetEntryLongDescription( SvTreeListEntry* pEntry ) const { return getAltLongDescText( pEntry, false); } void SdPageObjsTLB::InitEntry(SvTreeListEntry* pEntry, const OUString& rStr, const Image& rImg1, const Image& rImg2, SvLBoxButtonKind eButtonKind) { sal_uInt16 nColToHilite = 1; //0==Bitmap;1=="Spalte1";2=="Spalte2" SvTreeListBox::InitEntry( pEntry, rStr, rImg1, rImg2, eButtonKind ); SvLBoxString& rCol = static_cast(pEntry->GetItem( nColToHilite )); pEntry->ReplaceItem(o3tl::make_unique(rCol.GetText()), nColToHilite ); } void SdPageObjsTLB::SaveExpandedTreeItemState(SvTreeListEntry* pEntry, std::vector& vectTreeItem) { if (pEntry) { SvTreeListEntry* pListEntry = pEntry; while (pListEntry) { if (pListEntry->HasChildren()) { if (IsExpanded(pListEntry)) vectTreeItem.push_back(GetEntryText(pListEntry)); SvTreeListEntry* pChildEntry = FirstChild(pListEntry); SaveExpandedTreeItemState(pChildEntry, vectTreeItem); } pListEntry = pListEntry->NextSibling(); } } } void SdPageObjsTLB::Clear() { //Save the expanded tree item if (mbSaveTreeItemState) { maSelectionEntryText.clear(); maTreeItem.clear(); if (GetCurEntry()) maSelectionEntryText = GetSelectedEntry(); SvTreeListEntry* pEntry = FirstChild(nullptr); SaveExpandedTreeItemState(pEntry, maTreeItem); } return SvTreeListBox::Clear(); } OUString SdPageObjsTLB::GetObjectName( const SdrObject* pObject, const bool bCreate) const { OUString aRet; if ( pObject ) { aRet = pObject->GetName(); if (aRet.isEmpty() && dynamic_cast(pObject) != nullptr) aRet = static_cast< const SdrOle2Obj* >( pObject )->GetPersistName(); } if (bCreate && mbShowAllShapes && aRet.isEmpty() && pObject!=nullptr) { aRet = SdResId(STR_NAVIGATOR_SHAPE_BASE_NAME); aRet = aRet.replaceFirst("%1", OUString::number(pObject->GetOrdNum() + 1)); } return aRet; } /** * select a entry in TreeLB */ bool SdPageObjsTLB::SelectEntry( const OUString& rName ) { bool bFound = false; if( !rName.isEmpty() ) { SvTreeListEntry* pEntry = nullptr; OUString aTmp; for( pEntry = First(); pEntry && !bFound; pEntry = Next( pEntry ) ) { aTmp = GetEntryText( pEntry ); if( aTmp == rName ) { bFound = true; SetCurEntry( pEntry ); } } } return bFound; } /** * @return true if children of the specified string are selected */ bool SdPageObjsTLB::HasSelectedChildren( const OUString& rName ) { bool bChildren = false; if( !rName.isEmpty() ) { bool bFound = false; SvTreeListEntry* pEntry = nullptr; OUString aTmp; for( pEntry = First(); pEntry && !bFound; pEntry = Next( pEntry ) ) { aTmp = GetEntryText( pEntry ); if( aTmp == rName ) { bFound = true; bool bExpanded = IsExpanded( pEntry ); long nCount = GetChildSelectionCount( pEntry ); if( bExpanded && nCount > 0 ) bChildren = true; } } } return bChildren; } /** * Fill TreeLB with pages and objects */ void SdPageObjsTLB::Fill( const SdDrawDocument* pInDoc, bool bAllPages, const OUString& rDocName) { OUString aSelection; if( GetSelectionCount() > 0 ) { aSelection = GetSelectedEntry(); Clear(); } mpDoc = pInDoc; maDocName = rDocName; mbShowAllPages = bAllPages; mpMedium = nullptr; IconProvider aIconProvider; // first insert all pages including objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = mpDoc->GetPageCount(); while( nPage < nMaxPages ) { const SdPage* pPage = static_cast( mpDoc->GetPage( nPage ) ); if( (mbShowAllPages || pPage->GetPageKind() == PageKind::Standard) && (pPage->GetPageKind() != PageKind::Handout) ) //#94954# never list the normal handout page ( handout-masterpage is used instead ) { bool bPageExluded = pPage->IsExcluded(); bool bPageBelongsToShow = PageBelongsToCurrentShow (pPage); bPageExluded |= !bPageBelongsToShow; AddShapeList(*pPage, nullptr, pPage->GetName(), bPageExluded, nullptr, aIconProvider); } nPage++; } // then insert all master pages including objects if( mbShowAllPages ) { nPage = 0; const sal_uInt16 nMaxMasterPages = mpDoc->GetMasterPageCount(); while( nPage < nMaxMasterPages ) { const SdPage* pPage = static_cast( mpDoc->GetMasterPage( nPage ) ); AddShapeList(*pPage, nullptr, pPage->GetName(), false, nullptr, aIconProvider); nPage++; } } if( !aSelection.isEmpty() ) SelectEntry( aSelection ); else if (mbSaveTreeItemState && !maSelectionEntryText.isEmpty()) { SelectEntry(maSelectionEntryText); } } /** * We insert only the first entry. Children are created on demand. */ void SdPageObjsTLB::Fill( const SdDrawDocument* pInDoc, SfxMedium* pInMedium, const OUString& rDocName ) { mpDoc = pInDoc; // this object now owns the Medium mpMedium = pInMedium; maDocName = rDocName; Image aImgDocOpen(StockImage::Yes, BMP_DOC_OPEN); Image aImgDocClosed(StockImage::Yes, BMP_DOC_CLOSED); // insert document name InsertEntry( maDocName, aImgDocOpen, aImgDocClosed, nullptr, true, TREELIST_APPEND, reinterpret_cast< void* >( 1 ) ); } void SdPageObjsTLB::AddShapeList ( const SdrObjList& rList, SdrObject* pShape, const OUString& rsName, const bool bIsExcluded, SvTreeListEntry* pParentEntry, const IconProvider& rIconProvider) { Image aIcon (rIconProvider.maImgPage); if (bIsExcluded) aIcon = rIconProvider.maImgPageExcl; else if (pShape != nullptr) aIcon = rIconProvider.maImgGroup; void* pUserData (reinterpret_cast(1)); if (pShape != nullptr) pUserData = pShape; SvTreeListEntry* pEntry = InsertEntry( rsName, aIcon, aIcon, pParentEntry, false, TREELIST_APPEND, pUserData); 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 ) ); if( !aStr.isEmpty() ) { if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == OBJ_OLE2 ) { InsertEntry( aStr, maImgOle, maImgOle, pEntry, false, TREELIST_APPEND, pObj ); } else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == OBJ_GRAF ) { InsertEntry( aStr, maImgGraphic, maImgGraphic, pEntry, false, TREELIST_APPEND, pObj ); } else if (pObj->IsGroupObject()) { AddShapeList( *pObj->GetSubList(), pObj, aStr, false, pEntry, rIconProvider ); } else { InsertEntry( aStr, rIconProvider.maImgObjects, rIconProvider.maImgObjects, pEntry, false, TREELIST_APPEND, pObj ); } } } if( pEntry->HasChildren() ) { SetExpandedEntryBmp( pEntry, bIsExcluded ? rIconProvider.maImgPageObjsExcl : rIconProvider.maImgPageObjs); SetCollapsedEntryBmp( pEntry, bIsExcluded ? rIconProvider.maImgPageObjsExcl : rIconProvider.maImgPageObjs); if (mbSaveTreeItemState) { OUString strEntry = GetEntryText(pEntry); auto it = std::find(maTreeItem.begin(), maTreeItem.end(), strEntry); if (it != maTreeItem.end()) Expand( pEntry ); } else Expand( pEntry ); } } void SdPageObjsTLB::SetShowAllShapes ( const bool bShowAllShapes, const bool bFillList) { mbShowAllShapes = bShowAllShapes; if (bFillList) { if (mpMedium == nullptr) Fill(mpDoc, mbShowAllPages, maDocName); else Fill(mpDoc, mpMedium, maDocName); } } bool SdPageObjsTLB::IsEqualToShapeList(SvTreeListEntry*& pEntry, const SdrObjList& rList, const OUString& rListName) { if (!pEntry) return false; OUString aName = GetEntryText(pEntry); if (rListName != aName) return false; pEntry = Next(pEntry); 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 (!pEntry) return false; aName = GetEntryText(pEntry); if (aObjectName != aName) return false; if (pObj->IsGroupObject()) { bool bRet = IsEqualToShapeList(pEntry, *pObj->GetSubList(), aObjectName); if (!bRet) return false; } else pEntry = Next(pEntry); } } 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 SdPageObjsTLB::IsEqualToDoc( const SdDrawDocument* pInDoc ) { if( pInDoc ) mpDoc = pInDoc; if( !mpDoc ) return false; SvTreeListEntry* pEntry = First(); // compare all pages including the objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = mpDoc->GetPageCount(); while( nPage < nMaxPages ) { const SdPage* pPage = static_cast( mpDoc->GetPage( nPage ) ); if( pPage->GetPageKind() == PageKind::Standard ) { bool bRet = IsEqualToShapeList(pEntry, *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 !pEntry; } /** * @return selected string */ OUString SdPageObjsTLB::GetSelectedEntry() { return GetEntryText( GetCurEntry() ); } std::vector SdPageObjsTLB::GetSelectEntryList( const sal_uInt16 nDepth ) const { std::vector aEntries; SvTreeListEntry* pEntry = FirstSelected(); while( pEntry ) { sal_uInt16 nListDepth = GetModel()->GetDepth( pEntry ); if( nListDepth == nDepth ) aEntries.push_back(GetEntryText(pEntry)); pEntry = NextSelected( pEntry ); } return aEntries; } /** * Entries are inserted only by request (double click) */ void SdPageObjsTLB::RequestingChildren( SvTreeListEntry* pFileEntry ) { if( !pFileEntry->HasChildren() ) { if( GetBookmarkDoc() ) { SdrObject* pObj = nullptr; SvTreeListEntry* pPageEntry = nullptr; Image aImgPage(StockImage::Yes, BMP_PAGE); Image aImgPageObjs(StockImage::Yes, BMP_PAGEOBJS); Image aImgObjects(StockImage::Yes, BMP_OBJECTS); // document name already inserted // only insert all "normal" ? slides with objects sal_uInt16 nPage = 0; const sal_uInt16 nMaxPages = mpBookmarkDoc->GetPageCount(); while( nPage < nMaxPages ) { SdPage* pPage = static_cast( mpBookmarkDoc->GetPage( nPage ) ); if( pPage->GetPageKind() == PageKind::Standard ) { pPageEntry = InsertEntry( pPage->GetName(), aImgPage, aImgPage, pFileEntry, false, TREELIST_APPEND, reinterpret_cast< void* >( 1 ) ); 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() == OBJ_OLE2 ) { InsertEntry(aStr, maImgOle, maImgOle, pPageEntry); } else if( pObj->GetObjInventor() == SdrInventor::Default && pObj->GetObjIdentifier() == OBJ_GRAF ) { InsertEntry(aStr, maImgGraphic, maImgGraphic, pPageEntry); } else { InsertEntry(aStr, aImgObjects, aImgObjects, pPageEntry); } } } if( pPageEntry->HasChildren() ) { SetExpandedEntryBmp( pPageEntry, aImgPageObjs ); SetCollapsedEntryBmp( pPageEntry, aImgPageObjs ); } } nPage++; } } } else SvTreeListBox::RequestingChildren( pFileEntry ); } /** * Checks if it is a draw file and opens the BookmarkDoc depending of * the provided Docs */ SdDrawDocument* SdPageObjsTLB::GetBookmarkDoc(SfxMedium* pMed) { if ( !mpBookmarkDoc || (pMed && (!mpOwnMedium || mpOwnMedium->GetName() != pMed->GetName())) ) { // create a new BookmarkDoc if now one exists or if a new Medium is provided if (mpOwnMedium != pMed) { CloseBookmarkDoc(); } if (pMed) { // it looks that it is undefined if a Medium was set by Fill() already DBG_ASSERT( !mpMedium, "SfxMedium confusion!" ); delete mpMedium; mpMedium = nullptr; // take over this Medium (currently used only be Navigator) mpOwnMedium = pMed; } DBG_ASSERT( mpMedium || pMed, "No SfxMedium provided!" ); if( pMed ) { // in this mode the document is also owned and controlled by this instance mxBookmarkDocShRef = new ::sd::DrawDocShell(SfxObjectCreateMode::STANDARD, true, DocumentType::Impress); if (mxBookmarkDocShRef->DoLoad(pMed)) mpBookmarkDoc = mxBookmarkDocShRef->GetDoc(); else mpBookmarkDoc = nullptr; } else if ( mpMedium ) // 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 mpBookmarkDoc = const_cast(mpDoc)->OpenBookmarkDoc(mpMedium); if ( !mpBookmarkDoc ) { std::unique_ptr xErrorBox(Application::CreateMessageDialog(GetFrameWeld(), VclMessageType::Warning, VclButtonsType::Ok, SdResId(STR_READ_DATA_ERROR))); xErrorBox->run(); mpMedium = nullptr; //On failure the SfxMedium is invalid } } return mpBookmarkDoc; } /** * Close and delete bookmark document */ void SdPageObjsTLB::CloseBookmarkDoc() { if (mxBookmarkDocShRef.is()) { mxBookmarkDocShRef->DoClose(); mxBookmarkDocShRef.clear(); // Medium is owned by document, so it's destroyed already mpOwnMedium = nullptr; } else if ( mpBookmarkDoc ) { DBG_ASSERT( !mpOwnMedium, "SfxMedium confusion!" ); if ( mpDoc ) { // The document owns the Medium, so the Medium will be invalid after closing the document const_cast(mpDoc)->CloseBookmarkDoc(); mpMedium = nullptr; } } else { // perhaps mpOwnMedium provided, but no successful creation of BookmarkDoc delete mpOwnMedium; mpOwnMedium = nullptr; } mpBookmarkDoc = nullptr; } void SdPageObjsTLB::SelectHdl() { SvTreeListEntry* pEntry = FirstSelected(); mbLinkableSelected = true; while( pEntry && mbLinkableSelected ) { if( nullptr == pEntry->GetUserData() ) mbLinkableSelected = false; pEntry = NextSelected( pEntry ); } SvTreeListBox::SelectHdl(); if (mbSelectionHandlerNavigates) DoubleClickHdl(); } /** * Overloads RETURN with the functionality of DoubleClick */ void SdPageObjsTLB::KeyInput( const KeyEvent& rKEvt ) { const vcl::KeyCode& aKeyCode = rKEvt.GetKeyCode(); if ( m_pAccel->execute( aKeyCode ) ) // the accelerator consumed the event return; if( rKEvt.GetKeyCode().GetCode() == KEY_RETURN ) { // commented code from svtools/source/contnr/svimpbox.cxx SvTreeListEntry* pCursor = GetCurEntry(); if (!pCursor) return; if( pCursor->HasChildren() || pCursor->HasChildrenOnDemand() ) { if( IsExpanded( pCursor ) ) Collapse( pCursor ); else Expand( pCursor ); } DoubleClickHdl(); } else if (rKEvt.GetKeyCode().GetCode() == KEY_SPACE) { if (mpNavigator) { SvTreeListEntry* pNewEntry = GetCurEntry(); if (!pNewEntry) return; SvTreeListEntry* pParentEntry = GetParent(pNewEntry); if (!pParentEntry) return; Invalidate(); } } else SvTreeListBox::KeyInput( rKEvt ); } void SdPageObjsTLB::MouseButtonDown(const MouseEvent& rMEvt) { mbSelectionHandlerNavigates = rMEvt.GetClicks() == 1; comphelper::ScopeGuard aNavigationGuard([this]() { this->mbSelectionHandlerNavigates = false; }); mbNavigationGrabsFocus = rMEvt.GetClicks() != 1; comphelper::ScopeGuard aGrabGuard([this]() { this->mbNavigationGrabsFocus = true; }); SvTreeListBox::MouseButtonDown(rMEvt); } /** * StartDrag-Request */ void SdPageObjsTLB::StartDrag( sal_Int8, const Point& rPosPixel) { SvTreeListEntry* pEntry = GetEntry(rPosPixel); if (pEntry && mpNavigator && mpNavigator->GetNavigatorDragType() != NAVIGATOR_DRAGTYPE_NONE) { // Mark only the children of the page under the mouse as drop // targets. This prevents moving shapes from one page to another. // Select all entries and disable them as drop targets. SetSelectionMode(SelectionMode::Multiple); SetCursor(static_cast(nullptr)); SelectAll(true, false); EnableSelectionAsDropTarget(false); // Enable only the entries as drop targets that are children of the // page under the mouse. SvTreeListEntry* pParent = GetRootLevelParent(pEntry); if (pParent != nullptr) { SelectAll(false, false); Select(pParent); // for (SvTreeListEntry*pChild=FirstChild(pParent); pChild!=NULL; pChild=NextSibling(pChild)) // Select(pChild, sal_True); EnableSelectionAsDropTarget();//sal_False); } // Set selection back to the entry under the mouse. SelectAll(false, false); SetSelectionMode(SelectionMode::Single); Select(pEntry); // We can delete the Navigator from ExecuteDrag (when switching to // another document type), but that would kill the StarView MouseMove // Handler which is calling Command(). // For this reason, Drag&Drop is asynchronous. Application::PostUserEvent( LINK( this, SdPageObjsTLB, ExecDragHdl ), nullptr, true ); } } /** * Begin drag */ void SdPageObjsTLB::DoDrag() { if (mpNavigator) { ::sd::DrawDocShell* pDocShell = mpDoc->GetDocSh(); OUString aURL = INetURLObject( pDocShell->GetMedium()->GetPhysicalName(), INetProtocol::File ).GetMainURL( INetURLObject::DecodeMechanism::NONE ); NavigatorDragType eDragType = mpNavigator->GetNavigatorDragType(); aURL += "#" + GetSelectedEntry(); INetBookmark aBookmark( aURL, GetSelectedEntry() ); sal_Int8 nDNDActions = DND_ACTION_COPYMOVE; if( eDragType == NAVIGATOR_DRAGTYPE_LINK ) nDNDActions = DND_ACTION_LINK; // Either COPY *or* LINK, never both! else if (mpDoc->GetSdPageCount(PageKind::Standard) == 1) { // Can not move away the last slide in a document. nDNDActions = DND_ACTION_COPY; } SvTreeListBox::ReleaseMouse(); bIsInDrag = true; // Get the view. ::sd::ViewShell* pViewShell = GetViewShellForDocShell(*pDocShell); if (pViewShell == nullptr) { OSL_ASSERT(pViewShell!=nullptr); return; } sd::View* pView = pViewShell->GetView(); if (pView == nullptr) { OSL_ASSERT(pView!=nullptr); return; } // object is destroyed by internal reference mechanism SdTransferable* pTransferable = new SdPageObjsTLB::SdPageObjsTransferable( *this, aBookmark, *pDocShell, eDragType); SdrObject* pObject = nullptr; void* pUserData = GetCurEntry()->GetUserData(); if (pUserData != nullptr && pUserData != reinterpret_cast(1)) pObject = static_cast(pUserData); 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(*pTransferable, *pObject); pTransferable->SetView(pView); SD_MOD()->pTransferDrag = pTransferable; } // 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 { pTransferable->SetView(pView); SD_MOD()->pTransferDrag = pTransferable; } pTransferable->StartDrag( this, nDNDActions ); } } void SdPageObjsTLB::OnDragFinished() { if (mpNavigator) { MouseEvent aMEvt(mpNavigator->GetPointerPosPixel()); SvTreeListBox::MouseButtonUp(aMEvt); } bIsInDrag = false; } /** * AcceptDrop-Event */ sal_Int8 SdPageObjsTLB::AcceptDrop (const AcceptDropEvent& rEvent) { sal_Int8 nResult (DND_ACTION_NONE); if ( !bIsInDrag && IsDropFormatSupported( SotClipboardFormatId::SIMPLE_FILE ) ) { nResult = rEvent.mnAction; } else { SvTreeListEntry* pEntry = GetDropTarget(rEvent.maPosPixel); if (rEvent.mbLeaving || !CheckDragAndDropMode( this, rEvent.mnAction )) { ImplShowTargetEmphasis( pTargetEntry, false ); } else if( GetDragDropMode() == DragDropMode::NONE ) { SAL_WARN( "sc.ui", "SdPageObjsTLB::AcceptDrop(): no target" ); } else if (IsDropAllowed(pEntry)) { nResult = DND_ACTION_MOVE; // Draw emphasis. if (pEntry != pTargetEntry || !(nImpFlags & SvTreeListBoxFlags::TARGEMPH_VIS)) { ImplShowTargetEmphasis( pTargetEntry, false ); pTargetEntry = pEntry; ImplShowTargetEmphasis( pTargetEntry, true ); } } } // Hide emphasis when there is no valid drop action. if (nResult == DND_ACTION_NONE) ImplShowTargetEmphasis(pTargetEntry, false); return nResult; } /** * ExecuteDrop-Event */ sal_Int8 SdPageObjsTLB::ExecuteDrop( const ExecuteDropEvent& rEvt ) { sal_Int8 nRet = DND_ACTION_NONE; try { if( !bIsInDrag ) { if (mpNavigator) { TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable ); OUString aFile; if( aDataHelper.GetString( SotClipboardFormatId::SIMPLE_FILE, aFile ) && mpNavigator->InsertFile( aFile ) ) { nRet = rEvt.mnAction; } } } } catch (css::uno::Exception&) { DBG_UNHANDLED_EXCEPTION("sd"); } if (nRet == DND_ACTION_NONE) SvTreeListBox::ExecuteDrop(rEvt, this); return nRet; } /** * Handler for Dragging */ IMPL_LINK_NOARG(SdPageObjsTLB, ExecDragHdl, void*, void) { // as link, then it is allowed to asynchronous, without ImpMouseMoveMsg on // the stack, delete the Navigator DoDrag(); } bool SdPageObjsTLB::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 (mpDoc->getPresentationSettings().mbCustomShow) { // Get the current custom show. SdCustomShow* pCustomShow = nullptr; SdCustomShowList* pShowList = const_cast(mpDoc)->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; } TriState SdPageObjsTLB::NotifyMoving( SvTreeListEntry* pTarget, SvTreeListEntry* pEntry, SvTreeListEntry*& rpNewParent, sal_uLong& rNewChildPos) { SvTreeListEntry* pDestination = pTarget; while (GetParent(pDestination) != nullptr && GetParent(GetParent(pDestination)) != nullptr) pDestination = GetParent(pDestination); SdrObject* pTargetObject = static_cast(pDestination->GetUserData()); SdrObject* pSourceObject = static_cast(pEntry->GetUserData()); 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; else nNewPosition = pTargetObject->GetNavigationPosition() + 1; pObjectList->SetObjectNavigationPosition(*pSourceObject, nNewPosition); } // Update the tree list. if (GetParent(pDestination) == nullptr) { rpNewParent = pDestination; rNewChildPos = 0; } else { rpNewParent = GetParent(pDestination); rNewChildPos = SvTreeList::GetRelPos(pDestination) + 1; rNewChildPos += nCurEntrySelPos; nCurEntrySelPos++; } return TRISTATE_TRUE; } else return TRISTATE_FALSE; } SvTreeListEntry* SdPageObjsTLB::GetDropTarget (const Point& rLocation) { SvTreeListEntry* pEntry = SvTreeListBox::GetDropTarget(rLocation); if (pEntry == nullptr) return nullptr; if (GetParent(pEntry) == nullptr) { // Use page entry as insertion position. } else { // Go to second hierarchy level, i.e. top level shapes, // i.e. children of pages. while (GetParent(pEntry) != nullptr && GetParent(GetParent(pEntry)) != nullptr) pEntry = GetParent(pEntry); // Advance to next sibling. SvTreeListEntry* pNext; sal_uInt16 nDepth (0); do { pNext = NextVisible(pEntry, &nDepth); if (pNext != nullptr && nDepth > 0 && nDepth!=0xffff) pEntry = pNext; else break; } while (pEntry != nullptr); } return pEntry; } bool SdPageObjsTLB::IsDropAllowed (SvTreeListEntry const * pEntry) { if (pEntry == nullptr) return false; if ( ! IsDropFormatSupported(SdPageObjsTransferable::GetListBoxDropFormatId())) return false; if (pEntry->GetFlags() & SvTLEntryFlags::DISABLE_DROP) return false; return true; } void SdPageObjsTLB::AddShapeToTransferable ( SdTransferable& rTransferable, 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 = mpDoc->GetDocSh(); if (bIsDescriptorFillingPending && pDocShell!=nullptr) { pDocShell->FillTransferableObjectDescriptor(*pObjectDescriptor); } Point aDragPos (rObject.GetCurrentBoundRect().Center()); //Point aDragPos (0,0); pObjectDescriptor->maDragStartPos = aDragPos; // aObjectDescriptor.maSize = GetAllMarkedRect().GetSize(); if (pDocShell != nullptr) pObjectDescriptor->maDisplayName = pDocShell->GetMedium()->GetURLObject().GetURLNoPass(); else pObjectDescriptor->maDisplayName.clear(); rTransferable.SetStartPos(aDragPos); rTransferable.SetObjectDescriptor( std::move(pObjectDescriptor) ); } ::sd::ViewShell* SdPageObjsTLB::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); uno::Reference xFrameSupplier (xDesktop, uno::UNO_QUERY); if ( ! xFrameSupplier.is()) return nullptr; uno::Reference xFrameAccess (xFrameSupplier->getFrames(), uno::UNO_QUERY); if ( ! xFrameAccess.is()) return nullptr; for (sal_Int32 nIndex=0,nCount=xFrameAccess->getCount(); nIndex xFrame; if ( ! (xFrameAccess->getByIndex(nIndex) >>= xFrame)) continue; ::sd::DrawController* pController = dynamic_cast(xFrame->getController().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; } //===== IconProvider ========================================================== SdPageObjsTLB::IconProvider::IconProvider() : maImgPage(StockImage::Yes, BMP_PAGE), maImgPageExcl(StockImage::Yes, BMP_PAGE_EXCLUDED), maImgPageObjsExcl(StockImage::Yes, BMP_PAGEOBJS_EXCLUDED), maImgPageObjs(StockImage::Yes, BMP_PAGEOBJS), maImgObjects(StockImage::Yes, BMP_OBJECTS), maImgGroup(StockImage::Yes, BMP_GROUP) { } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */