/* -*- 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 <sal/types.h>
#include <sal/log.hxx>
#include <sot/formats.hxx>
#include <sot/storage.hxx>
#include <vcl/weld.hxx>
#include <svl/urihelper.hxx>
#include <svx/svditer.hxx>
#include <sfx2/docfile.hxx>
#include <svx/svdoole2.hxx>
#include <vcl/svapp.hxx>
#include <vcl/builderfactory.hxx>
#include <cusshow.hxx>
#include <sfx2/childwin.hxx>
#include <sfx2/viewfrm.hxx>
#include <strmname.h>
#include <sdtreelb.hxx>
#include <DrawDocShell.hxx>
#include <drawdoc.hxx>
#include <sdpage.hxx>
#include <sdmod.hxx>
#include <sdresid.hxx>
#include <navigatr.hxx>
#include <strings.hrc>
#include <bitmaps.hlst>
#include <customshowlist.hxx>
#include <ViewShell.hxx>
#include <DrawController.hxx>
#include <ViewShellBase.hxx>
#include <com/sun/star/embed/XEmbedPersist.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/frame/XFramesSupplier.hpp>
#include <svtools/acceleratorexecute.hxx>
#include <svtools/embedtransfer.hxx>
#include <svtools/svlbitm.hxx>
#include <svtools/treelistentry.hxx>
#include <comphelper/servicehelper.hxx>
#include <comphelper/processfactory.hxx>
#include <tools/diagnose_ex.h>
#include <o3tl/make_unique.hxx>
#include <comphelper/scopeguard.hxx>
using namespace com::sun::star;
class SdPageObjsTLB::IconProvider
{
public:
IconProvider();
// Regular icons.
Image maImgPage;
Image maImgPageExcl;
Image maImgPageObjsExcl;
Image maImgPageObjs;
Image maImgObjects;
Image maImgGroup;
};
bool SdPageObjsTLB::bIsInDrag = false;
bool SdPageObjsTLB::IsInDrag()
{
return bIsInDrag;
}
SotClipboardFormatId SdPageObjsTLB::SdPageObjsTransferable::mnListBoxDropFormatId = static_cast<SotClipboardFormatId>(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<sal_Int64>(reinterpret_cast<sal_IntPtr>(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<SdPageObjsTLB::SdPageObjsTransferable*>(
sal::static_int_cast<sal_uIntPtr>(
xUnoTunnel->getSomething( SdPageObjsTLB::SdPageObjsTransferable::getUnoTunnelId()) ) );
}
catch( const css::uno::Exception& )
{
}
return nullptr;
}
SotClipboardFormatId SdPageObjsTLB::SdPageObjsTransferable::GetListBoxDropFormatId()
{
if (mnListBoxDropFormatId == static_cast<SotClipboardFormatId>(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 )
, bisInSdNavigatorWin ( false )
, mpParent ( pParentWin )
, mpDoc ( nullptr )
, mpBookmarkDoc ( nullptr )
, mpMedium ( nullptr )
, mpOwnMedium ( nullptr )
, maImgOle ( BitmapEx(BMP_OLE) )
, maImgGraphic ( BitmapEx(BMP_GRAPHIC) )
, mbLinkableSelected ( false )
, mpDropNavWin ( nullptr )
, mpFrame ( nullptr )
, 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(BitmapEx(BMP_EXPAND)), Image(BitmapEx(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::SetViewFrame( SfxViewFrame* pViewFrame )
{
mpFrame = 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;
mpParent.clear();
mpDropNavWin.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<const SdPage*>( 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<SvLBoxString&>(pEntry->GetItem( nColToHilite ));
pEntry->ReplaceItem(o3tl::make_unique<SvLBoxString>(rCol.GetText()), nColToHilite );
}
void SdPageObjsTLB::SaveExpandedTreeItemState(SvTreeListEntry* pEntry, std::vector<OUString>& 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<const SdrOle2Obj* >(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<const SdPage*>( 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<const SdPage*>( 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=Image(BitmapEx(BMP_DOC_OPEN));
Image aImgDocClosed=Image(BitmapEx(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<void*>(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)
{
std::vector<OUString>::iterator iteStart = maTreeItem.begin();
while (iteStart != maTreeItem.end())
{
OUString strEntry = GetEntryText(pEntry);
if (*iteStart == strEntry)
{
Expand( pEntry );
break;
}
++iteStart;
}
}
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<const SdPage*>( 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<OUString> SdPageObjsTLB::GetSelectEntryList( const sal_uInt16 nDepth ) const
{
std::vector<OUString> 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 = Image(BitmapEx(BMP_PAGE));
Image aImgPageObjs = Image(BitmapEx(BMP_PAGEOBJS));
Image aImgObjects = Image(BitmapEx(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<SdPage*>( 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<SdDrawDocument*>(mpDoc)->OpenBookmarkDoc(mpMedium);
if ( !mpBookmarkDoc )
{
std::unique_ptr<weld::MessageDialog> 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<SdDrawDocument*>(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(bisInSdNavigatorWin)
{
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)
{
SdNavigatorWin* pNavWin = nullptr;
SvTreeListEntry* pEntry = GetEntry(rPosPixel);
if (mpFrame->HasChildWindow(SID_NAVIGATOR))
{
SfxChildWindow* pWnd = mpFrame->GetChildWindow(SID_NAVIGATOR);
pNavWin = pWnd ? static_cast<SdNavigatorWin*>(pWnd->GetContextWindow(SD_MOD())) : nullptr;
}
if (pEntry != nullptr
&& pNavWin !=nullptr
&& pNavWin == mpParent
&& pNavWin->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<SvTreeListEntry*>(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()
{
SfxChildWindow* pWnd = mpFrame->HasChildWindow(SID_NAVIGATOR) ? mpFrame->GetChildWindow(SID_NAVIGATOR) : nullptr;
mpDropNavWin = pWnd ? static_cast<SdNavigatorWin*>(pWnd->GetContextWindow(SD_MOD())) : nullptr;
if( mpDropNavWin )
{
::sd::DrawDocShell* pDocShell = mpDoc->GetDocSh();
OUString aURL = INetURLObject( pDocShell->GetMedium()->GetPhysicalName(), INetProtocol::File ).GetMainURL( INetURLObject::DecodeMechanism::NONE );
NavigatorDragType eDragType = mpDropNavWin->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<void*>(1))
pObject = static_cast<SdrObject*>(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( mpFrame->HasChildWindow( SID_NAVIGATOR ) )
{
SfxChildWindow* pWnd = mpFrame->GetChildWindow(SID_NAVIGATOR);
SdNavigatorWin* pNewNavWin = pWnd ? static_cast<SdNavigatorWin*>(pWnd->GetContextWindow(SD_MOD())) : nullptr;
if (mpDropNavWin == pNewNavWin)
{
MouseEvent aMEvt( mpDropNavWin->GetPointerPosPixel() );
SvTreeListBox::MouseButtonUp( aMEvt );
}
}
mpDropNavWin = nullptr;
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 )
{
SdNavigatorWin* pNavWin = nullptr;
sal_uInt16 nId = SID_NAVIGATOR;
if (mpFrame->HasChildWindow(nId))
{
SfxChildWindow* pWnd = mpFrame->GetChildWindow(nId);
pNavWin = pWnd ? static_cast<SdNavigatorWin*>(pWnd->GetContextWindow(SD_MOD())) : nullptr;
}
if( pNavWin && ( pNavWin == mpParent ) )
{
TransferableDataHelper aDataHelper( rEvt.maDropEvent.Transferable );
OUString aFile;
if( aDataHelper.GetString( SotClipboardFormatId::SIMPLE_FILE, aFile ) &&
static_cast<SdNavigatorWin*>(mpParent.get())->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 <TRUE/> 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<SdDrawDocument*>(mpDoc)->GetCustomShowList();
if (pShowList != nullptr)
{
sal_uLong nCurrentShowIndex = pShowList->GetCurPos();
pCustomShow = (*pShowList)[nCurrentShowIndex];
}
// 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; i<nPageCount && !bBelongsToShow; i++)
if (pPage == pCustomShow->PagesVector()[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<SdrObject*>(pDestination->GetUserData());
SdrObject* pSourceObject = static_cast<SdrObject*>(pEntry->GetUserData());
if (pSourceObject == reinterpret_cast<SdrObject*>(1))
pSourceObject = nullptr;
if (pTargetObject != nullptr && pSourceObject != nullptr)
{
SdrPage* pObjectList = pSourceObject->getSdrPageFromSdrObject();
if (pObjectList != nullptr)
{
sal_uInt32 nNewPosition;
if (pTargetObject == reinterpret_cast<SdrObject*>(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<TransferableObjectDescriptor> pObjectDescriptor(new TransferableObjectDescriptor);
bool bIsDescriptorFillingPending (true);
const SdrOle2Obj* pOleObject = dynamic_cast<const SdrOle2Obj*>(&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<uno::XComponentContext> xContext( ::comphelper::getProcessComponentContext());
uno::Reference<frame::XDesktop2> xDesktop = frame::Desktop::create(xContext);
uno::Reference<frame::XFramesSupplier> xFrameSupplier (xDesktop, uno::UNO_QUERY);
if ( ! xFrameSupplier.is())
return nullptr;
uno::Reference<container::XIndexAccess> xFrameAccess (xFrameSupplier->getFrames(), uno::UNO_QUERY);
if ( ! xFrameAccess.is())
return nullptr;
for (sal_Int32 nIndex=0,nCount=xFrameAccess->getCount(); nIndex<nCount; ++nIndex)
{
uno::Reference<frame::XFrame> xFrame;
if ( ! (xFrameAccess->getByIndex(nIndex) >>= xFrame))
continue;
::sd::DrawController* pController = dynamic_cast<sd::DrawController*>(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<sd::ViewShell> 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(BitmapEx(BMP_PAGE)),
maImgPageExcl(BitmapEx(BMP_PAGE_EXCLUDED)),
maImgPageObjsExcl(BitmapEx(BMP_PAGEOBJS_EXCLUDED)),
maImgPageObjs(BitmapEx(BMP_PAGEOBJS)),
maImgObjects(BitmapEx(BMP_OBJECTS)),
maImgGroup(BitmapEx(BMP_GROUP))
{
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V654 The condition 'pEntry != nullptr' of loop is always true.