/* -*- 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 .
*/
/** * @return true if children of the specified string are selected
*/ bool SdPageObjsTLV::HasSelectedChildren( std::u16string_view rName )
{ bool bChildren = false;
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<weld::TreeIter> 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));
}
}
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) returnfalse;
aName = m_xTreeView->get_text(*rEntry);
if (aObjectName != aName) returnfalse;
if (pObj->IsGroupObject())
{ bool bRet = IsEqualToShapeList(rEntry, *pObj->GetSubList(), aObjectName); if (!bRet) returnfalse;
} else
{ if (!m_xTreeView->iter_next(*rEntry))
rEntry.reset();
}
}
}
returntrue;
}
/** * 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 ) returnfalse;
sd::DrawViewShell* pDrawViewShell = lcl_getDrawViewShell(m_pDoc); if (!pDrawViewShell) returnfalse;
PageKind eDrawViewShellPageKind = pDrawViewShell->GetPageKind(); if (eDrawViewShellPageKind != PageKind::Standard && eDrawViewShellPageKind != PageKind::Notes) returnfalse;
std::unique_ptr<weld::TreeIter> 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<const SdPage*>( m_pDoc->GetPage( nPage ) ); if (pPage->GetPageKind() == eDrawViewShellPageKind)
{ bool bRet = IsEqualToShapeList(xEntry, *pPage, pPage->GetName()); if (!bRet) returnfalse;
}
nPage++;
} // If there are still entries in the listbox, // then objects (with names) or pages were deleted return !xEntry;
}
IMPL_LINK(SdPageObjsTLV, CommandHdl, const CommandEvent&, rCEvt, bool)
{ if (m_bEditing)
{ // Set the editing flag false here because gtk3 in-place editing ends but EditedEntryHdl // doesn't get called. This isn't needed for sal in-place editing because EditedEntryHdl // gets called when focus is lost.
m_bEditing = false;
}
if (rCEvt.GetCommand() == CommandEventId::ContextMenu)
{
m_xTreeView->grab_focus();
IMPL_LINK(SdPageObjsTLV, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{ if (m_bEditing) returnfalse;
const vcl::KeyCode& rKeyCode = rKEvt.GetKeyCode(); if (m_xAccel->execute(rKeyCode))
{ // the accelerator consumed the event returntrue;
} if (rKeyCode.GetCode() == KEY_RETURN)
{
std::unique_ptr<weld::TreeIter> 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_bNavigationGrabsFocus = true;
m_aRowActivatedHdl.Call(*m_xTreeView);
m_bNavigationGrabsFocus = false; returntrue;
} bool bRet = m_aKeyPressHdl.Call(rKEvt); return bRet;
}
IMPL_LINK(SdPageObjsTLV, MousePressHdl, const MouseEvent&, rMEvt, bool)
{ // Don't set m_bEditing false here. Sal in-place editing doesn't like that because the in-place // editing mouse presses also end up here. if (m_bEditing) returnfalse;
SdrObject* pObject = nullptr;
sal_Int64 nUserData = bUserData ? m_xTreeView->get_id(*xEntry).toInt64() : 0; if (nUserData != 1)
pObject = reinterpret_cast<SdrObject*>(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);
SdModule::get()->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);
SdModule::get()->pTransferDrag = m_xHelper.get();
}
/** * 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<weld::TreeIter> xTarget(m_rTreeView.make_iterator()); if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), true)) return DND_ACTION_NONE;
// disallow when root is drop target if (m_rTreeView.get_iter_depth(*xTarget) == 0) return DND_ACTION_NONE;
// disallow if there is no source entry selected
std::unique_ptr<weld::TreeIter> xSource(m_rTreeView.make_iterator()); if (!m_rTreeView.get_selected(xSource.get())) return DND_ACTION_NONE;
// disallow when root is source if (m_rTreeView.get_iter_depth(*xSource) == 0) return DND_ACTION_NONE;
// disallow when the source is the parent or ancestral parent of the target
std::unique_ptr<weld::TreeIter> xTargetParent(m_rTreeView.make_iterator(xTarget.get())); while (m_rTreeView.get_iter_depth(*xTargetParent) > 1)
{ if (!m_rTreeView.iter_parent(*xTargetParent) ||
m_rTreeView.iter_compare(*xSource, *xTargetParent) == 0) return DND_ACTION_NONE;
}
// disallow drop when source and target are not within the same page
std::unique_ptr<weld::TreeIter> xSourcePage(m_rTreeView.make_iterator(xSource.get()));
std::unique_ptr<weld::TreeIter> xTargetPage(m_rTreeView.make_iterator(xTarget.get())); while (m_rTreeView.get_iter_depth(*xTargetPage))
m_rTreeView.iter_parent(*xTargetPage); while (m_rTreeView.get_iter_depth(*xSourcePage))
m_rTreeView.iter_parent(*xSourcePage); if (m_rTreeView.iter_compare(*xTargetPage, *xSourcePage) != 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<weld::TreeIter> xSource(m_rTreeView.make_iterator()); if (!m_rTreeView.get_selected(xSource.get())) return DND_ACTION_NONE;
std::unique_ptr<weld::TreeIter> xTarget(m_rTreeView.make_iterator()); if (!m_rTreeView.get_dest_row_at_pos(rEvt.maPosPixel, xTarget.get(), false)) return DND_ACTION_NONE;
auto nIterCompare = m_rTreeView.iter_compare(*xSource, *xTarget); if (nIterCompare == 0)
{ // drop position is the same as source position return DND_ACTION_NONE;
}
int nTargetPos = m_rTreeView.get_iter_index_in_parent(*xTarget);
// Make the tree view what the model will be when it is changed below.
m_rTreeView.move_subtree(*xSource, xTargetParent.get(), nTargetPos);
m_rTreeView.iter_previous_sibling(*xTarget);
m_rTreeView.set_cursor(*xTarget);
// Remove and insert are required for moving objects into and out of groups. // PutMarked... by itself would suffice if this wasn't allowed.
// Remove the source object from source parent list and insert it in the target parent list.
SdrObject* pSourceParentObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xSourceParent));
SdrObject* pTargetParentObject = weld::fromId<SdrObject*>(m_rTreeView.get_id(*xTargetParent));
// Presumably there is need for a hard reference to hold on to the removed object so it is // guaranteed to be valid for insert back into an object list.
rtl::Reference<SdrObject> rSourceObject;
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& )
{
}
}
try
{ // Get a component enumeration from the desktop and search it for documents. const uno::Reference<uno::XComponentContext>& xContext( ::comphelper::getProcessComponentContext());
uno::Reference<container::XIndexAccess> xFrameAccess = xDesktop->getFrames(); 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;
auto xController = xFrame->getController();
::sd::DrawController* pController = dynamic_cast<sd::DrawController*>(xController.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;
}
// Did the name change? if (m_xTreeView->get_text(rIterString.first) == rIterString.second) returntrue;
// If the new name is empty or not unique, start editing again. if (rIterString.second.isEmpty() || m_pDoc->GetObj(rIterString.second)
|| m_pDoc->IsPageNameUnique(rIterString.second))
{
std::unique_ptr<weld::TreeIter> xEntry(m_xTreeView->make_iterator(&rIterString.first));
Application::PostUserEvent(LINK(this, SdPageObjsTLV, EditEntryAgain), xEntry.release()); returnfalse;
}
// set the new name constauto aEntryId = m_xTreeView->get_id(rIterString.first); if (aEntryId.toInt64() == 1)
{ // page name if (::sd::DrawDocShell* pDocShell = m_pDoc->GetDocSh())
{ if (::sd::ViewShell* pViewShell = GetViewShellForDocShell(*pDocShell))
{
SdPage* pPage = pViewShell->GetActualPage();
pPage->SetName(rIterString.second);
}
}
} elseif (SdrObject* pCursorEntryObject = weld::fromId<SdrObject*>(aEntryId))
{ // object name
pCursorEntryObject->SetName(rIterString.second);
}
returntrue;
}
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)); returnfalse;
}
if( eDragType == NAVIGATOR_DRAGTYPE_LINK )
nDNDActions = DND_ACTION_LINK; // Either COPY *or* LINK, never both! elseif (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(std::move(aBookmark), *pDocShell, eDragType));
rtl::Reference<TransferDataContainer> xHelper(m_xHelper);
m_xTreeView->enable_drag_source(xHelper, nDNDActions);
}
/** * 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;
} elseif ( 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<SdDrawDocument*>(m_pDoc)->OpenBookmarkDoc(m_pMedium);
if ( !m_pBookmarkDoc )
{
std::unique_ptr<weld::MessageDialog> 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;
/** * 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;
} elseif (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<SdDrawDocument*>(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 <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 (m_pDoc->getPresentationSettings().mbCustomShow)
{ // Get the current custom show.
SdCustomShow* pCustomShow = nullptr;
SdCustomShowList* pShowList = const_cast<SdDrawDocument*>(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; i<nPageCount && !bBelongsToShow; i++) if (pPage == pCustomShow->PagesVector()[i])
bBelongsToShow = true;
}
}
/** * 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;
/** * select an entry in TreeLB
*/ bool SdPageObjsTLV::SelectEntry( std::u16string_view rName )
{ bool bFound = false;
if (!rName.empty())
{
std::unique_ptr<weld::TreeIter> 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;
}
void SdPageObjsTLV::SelectEntry(const SdrObject *pObj)
{ if (pObj)
{
m_xTreeView->all_foreach([this, &pObj](weld::TreeIter& rEntry){ if (weld::fromId<SdrObject*>(m_xTreeView->get_id(rEntry)) == pObj)
{ // Only scroll to the row of the first selected. And only when the treeview // doesn't have the focus. if (!m_xTreeView->has_focus() && m_xTreeView->get_selected_rows().empty())
m_xTreeView->set_cursor(rEntry);
m_xTreeView->select(rEntry); returntrue;
} returnfalse;
});
}
}
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();
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.