/* -*- 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 .
*/
using ::com::sun::star::uno::UNO_QUERY; using ::com::sun::star::uno::UNO_QUERY_THROW; using ::com::sun::star::uno::Any; using ::com::sun::star::uno::Reference; using ::com::sun::star::uno::Exception; using ::com::sun::star::uno::XInterface; using ::com::sun::star::text::XTextRange; using ::com::sun::star::drawing::XShape; using ::com::sun::star::drawing::XShapes; using ::com::sun::star::drawing::XDrawPage; using ::com::sun::star::container::XChild; using ::com::sun::star::container::XIndexAccess; using ::com::sun::star::container::XEnumerationAccess; using ::com::sun::star::container::XEnumeration; using ::com::sun::star::beans::XPropertySet; using ::com::sun::star::beans::XPropertySetInfo;
namespace sd {
// go recursively through all shapes in the given XShapes collection and return true as soon as the // given shape is found. nIndex is incremented for each shape with the same shape type as the given // shape is found until the given shape is found. staticbool getShapeIndex( const Reference< XShapes >& xShapes, const Reference< XShape >& xShape, sal_Int32& nIndex )
{ const sal_Int32 nCount = xShapes->getCount();
sal_Int32 n; for( n = 0; n < nCount; n++ )
{
Reference< XShape > xChild;
xShapes->getByIndex( n ) >>= xChild; if( xChild == xShape ) returntrue;
// returns the index of the shape type from the given shape static sal_Int32 getShapeIndex( const Reference< XShape >& xShape )
{
Reference< XChild > xChild( xShape, UNO_QUERY );
Reference< XShapes > xPage;
rRenderContext.Push();
rRenderContext.SetFillColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogColor());
rRenderContext.SetLineColor(); // fill the background with the dialog bg color
rRenderContext.DrawRect(aOutRect);
// Erase the four corner pixels to make the rectangle appear rounded.
rRenderContext.SetLineColor(rRenderContext.GetSettings().GetStyleSettings().GetWindowColor());
rRenderContext.DrawPixel(aOutRect.TopLeft());
rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Top()));
rRenderContext.DrawPixel(Point(aOutRect.Left(), aOutRect.Bottom()));
rRenderContext.DrawPixel(Point(aOutRect.Right(), aOutRect.Bottom()));
// draw the category title
int nVertBorder = ((aSize.Height() - rRenderContext.GetTextHeight()) >> 1); int nHorzBorder = rRenderContext.LogicToPixel(Size(3, 3), MapMode(MapUnit::MapAppFont)).Width();
// Draw the text with the dialog text color
rRenderContext.SetTextColor(rRenderContext.GetSettings().GetStyleSettings().GetDialogTextColor());
rRenderContext.DrawText(aOutRect, rRenderContext.GetEllipsisString(msDescription, aOutRect.GetWidth()));
rRenderContext.Pop();
}
if (nAccept != DND_ACTION_NONE)
{ // to enable the autoscroll when we're close to the edges
weld::TreeView& rWidget = m_rTreeView.get_widget();
rWidget.get_dest_row_at_pos(rEvt.maPosPixel, nullptr, true);
}
// D'n'D #1: Record selected effects for drag'n'drop.
IMPL_LINK(CustomAnimationList, DragBeginHdl, bool&, rUnsetDragIcon, bool)
{
rUnsetDragIcon = false;
// Record which effects are selected: // Since NextSelected(..) iterates through the selected items in the order they // were selected, create a sorted list for simpler drag'n'drop algorithms.
mDndEffectsSelected.clear();
mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
mDndEffectsSelected.emplace_back(mxTreeView->make_iterator(&rEntry)); returnfalse;
});
// Note: pEntry is the effect with focus (if multiple effects are selected)
mxDndEffectDragging = mxTreeView->make_iterator(); if (!mxTreeView->get_cursor(mxDndEffectDragging.get()))
mxDndEffectDragging.reset();
// Allow normal processing. returnfalse;
}
// D'n'D #3: Called each time mouse moves during drag
sal_Int8 CustomAnimationList::AcceptDrop( const AcceptDropEvent& rEvt )
{
sal_Int8 ret = DND_ACTION_NONE;
constbool bIsMove = DND_ACTION_MOVE == rEvt.mnAction; if (mxDndEffectDragging && !rEvt.mbLeaving && bIsMove)
ret = DND_ACTION_MOVE; return ret;
}
// D'n'D #5: Tell model to update effect order.
sal_Int8 CustomAnimationList::ExecuteDrop(const ExecuteDropEvent& rEvt)
{
std::unique_ptr<weld::TreeIter> xDndEffectInsertBefore(mxTreeView->make_iterator()); if (!mxTreeView->get_dest_row_at_pos(rEvt.maPosPixel, xDndEffectInsertBefore.get(), true))
xDndEffectInsertBefore.reset();
// Callback to observer to have it update the model. // If pTarget is null, pass nullptr to indicate end of list.
mpController->onDragNDropComplete(
std::move(aEffects),
pTarget ? pTarget->getEffect() : nullptr );
// NOTE: Don't call default handler because all required // move operations have been completed here to update the model. return DND_ACTION_NONE;
}
CustomAnimationList::~CustomAnimationList()
{ if (mnPostExpandEvent)
{
Application::RemoveUserEvent(mnPostExpandEvent);
mnPostExpandEvent = nullptr;
}
if (mnPostCollapseEvent)
{
Application::RemoveUserEvent(mnPostCollapseEvent);
mnPostCollapseEvent = nullptr;
}
if( mpMainSequence )
mpMainSequence->removeListener( this );
clear();
}
IMPL_LINK(CustomAnimationList, KeyInputHdl, const KeyEvent&, rKEvt, bool)
{ constint nKeyCode = rKEvt.GetKeyCode().GetCode(); switch (nKeyCode)
{ case KEY_DELETE:
mpController->onContextMenu(u"remove"_ustr); returntrue; case KEY_INSERT:
mpController->onContextMenu(u"create"_ustr); returntrue; case KEY_SPACE:
{
std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator(); if (mxTreeView->get_cursor(xEntry.get()))
{ auto aRect = mxTreeView->get_row_area(*xEntry); const Point aPos(aRect.getOpenWidth() / 2, aRect.getOpenHeight() / 2); const CommandEvent aCEvt(aPos, CommandEventId::ContextMenu);
CommandHdl(aCEvt); returntrue;
}
}
} returnfalse;
}
/** selects or deselects the given effect.
Selections of other effects are not changed */ void CustomAnimationList::select( const CustomAnimationEffectPtr& pEffect )
{
CustomAnimationListEntryItem* pEntry = nullptr;
std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator(); if (mxTreeView->get_iter_first(*xEntry))
{ do
{
CustomAnimationListEntryItem* pTestEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry)); if (pTestEntry->getEffect() == pEffect)
{
mxTreeView->select(*xEntry);
mxTreeView->scroll_to_row(*xEntry);
pEntry = pTestEntry; break;
}
} while (mxTreeView->iter_next(*xEntry));
}
// restore selection state, expand state, and current-entry (under cursor) if (mxTreeView->get_iter_first(*xEntry))
{ do
{
CustomAnimationListEntryItem* pEntry = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xEntry));
CustomAnimationEffectPtr pEffect( pEntry->getEffect() ); if (pEffect)
{ // Any effects that were visible should still be visible, so expand their parents. // (a previously expanded parent may have moved leaving a child to now be the new parent to expand) if( std::find( aVisible.begin(), aVisible.end(), pEffect ) != aVisible.end() )
{ if (mxTreeView->get_iter_depth(*xEntry))
{
std::unique_ptr<weld::TreeIter> xParentEntry = mxTreeView->make_iterator(xEntry.get());
mxTreeView->iter_parent(*xParentEntry);
mxTreeView->expand_row(*xParentEntry);
}
}
// Restore the cursor, as it may deselect other effects wait until // after the loop to reset the selection if( pEffect == aCurrent )
mxTreeView->set_cursor(*xEntry);
if (pEffect == pFirstSelEffect)
nFirstSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
if (pEffect == pLastSelEffect)
nLastSelNew = weld::GetAbsPos(*mxTreeView, *xEntry);
}
} while (mxTreeView->iter_next(*xEntry));
}
// tdf#147032 unselect what previous set_cursor may have caused to get selected as a side-effect
mxTreeView->unselect_all(); for (constauto& rEntry : aNewSelection)
mxTreeView->select(*rEntry);
// Scroll to a selected entry, depending on where the selection moved. constbool bMoved = nFirstSelNew != nFirstSelOld; constbool bMovedUp = nFirstSelNew < nFirstSelOld; constbool bMovedDown = nFirstSelNew > nFirstSelOld;
if( bMoved && nLastSelOld < nFirstVis && nLastSelNew < nFirstVis )
{ // The selection is above the visible area. // Scroll up to show the last few selected entries. if( nLastSelNew - (nLastVis - nFirstVis) > nFirstSelNew)
{ // The entries in the selection range can't fit in view. // Scroll so the last selected entry is last in view.
mxTreeView->vadjustment_set_value(nLastSelNew - (nLastVis - nFirstVis));
} else
mxTreeView->vadjustment_set_value(nFirstSelNew);
} elseif( bMoved && nFirstSelOld > nLastVis && nFirstSelNew > nLastVis )
{ // The selection is below the visible area. // Scroll down to the first few selected entries.
mxTreeView->vadjustment_set_value(nFirstSelNew);
} elseif( bMovedUp && nFirstSelOld <= nFirstVis )
{ // A visible entry has moved up out of view; scroll up one.
mxTreeView->vadjustment_set_value(nFirstVis - 1);
} elseif( bMovedDown && nLastSelOld >= nLastVis )
{ // An entry has moved down out of view; scroll down one.
mxTreeView->vadjustment_set_value(nFirstVis + 1);
} elseif ( nFirstVis != -1 )
{ // The selection is still in view, or it hasn't moved.
mxTreeView->vadjustment_set_value(nFirstVis);
}
}
// if this effect has the same target and group-id as the last root effect, // the last root effect is also this effects parent if (mxLastParentEntry && nGroupId != -1 && mxLastTargetShape == xTargetShape && mnLastGroupId == nGroupId)
xParentEntry = mxTreeView->make_iterator(mxLastParentEntry.get());
// create an entry for the effect
std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator();
// and the new root entry becomes the possible next group header
mxLastTargetShape = std::move(xTargetShape);
mnLastGroupId = nGroupId;
mxLastParentEntry = std::move(xEntry);
}
} catch (const Exception&)
{
TOOLS_WARN_EXCEPTION( "sd", "sd::CustomAnimationList::append()" );
}
}
// Notify controller to refresh UI when we are notified of selection change from base class void CustomAnimationList::Select()
{ if( mbIgnorePaint ) return;
mpController->onSelect();
}
IMPL_LINK_NOARG(CustomAnimationList, PostExpandHdl, void*, void)
{
std::unique_ptr<weld::TreeIter> xEntry = mxTreeView->make_iterator(); if (mxTreeView->get_selected(xEntry.get()))
{ for (bool bChild = mxTreeView->iter_children(*xEntry); bChild; bChild = mxTreeView->iter_next_sibling(*xEntry))
{ if (!mxTreeView->is_selected(*xEntry))
mxTreeView->select(*xEntry);
}
}
// Notify controller that selection has changed (it should update the UI)
mpController->onSelect();
mnPostExpandEvent = nullptr;
}
IMPL_LINK(CustomAnimationList, ExpandHdl, const weld::TreeIter&, rParent, bool)
{ // If expanded entry is selected, then select its children too afterwards. if (mxTreeView->is_selected(rParent) && !mnPostExpandEvent) {
mnPostExpandEvent = Application::PostUserEvent(LINK(this, CustomAnimationList, PostExpandHdl));
}
returntrue;
}
IMPL_LINK_NOARG(CustomAnimationList, PostCollapseHdl, void*, void)
{ // Deselect all entries as SvTreeListBox::Collapse selects the last // entry to have focus (or its parent), which is not desired
mxTreeView->unselect_all();
// Restore selection state for entries which are still visible for (constauto &pEntry : lastSelectedEntries)
{ if (weld::IsEntryVisible(*mxTreeView, *pEntry))
mxTreeView->select(*pEntry);
}
lastSelectedEntries.clear();
// Notify controller that selection has changed (it should update the UI)
mpController->onSelect();
mnPostCollapseEvent = nullptr;
}
IMPL_LINK_NOARG(CustomAnimationList, CollapseHdl, const weld::TreeIter&, bool)
{ if (!mnPostCollapseEvent)
{ // weld::TreeView::collapse() discards multi-selection state // of list entries, so first save current selection state
mxTreeView->selected_foreach([this](weld::TreeIter& rEntry){
lastSelectedEntries.emplace_back(mxTreeView->make_iterator(&rEntry)); returnfalse;
});
// if the selected effect is not expanded and has children // we say that the children are automatically selected if (!mxTreeView->get_row_expanded(rEntry) && mxTreeView->iter_has_child(rEntry))
{
std::unique_ptr<weld::TreeIter> xChild = mxTreeView->make_iterator(&rEntry);
(void)mxTreeView->iter_children(*xChild);
do
{ if (!mxTreeView->is_selected(*xChild))
{
CustomAnimationListEntryItem* pChild = weld::fromId<CustomAnimationListEntryItem*>(mxTreeView->get_id(*xChild)); const CustomAnimationEffectPtr& pChildEffect( pChild->getEffect() ); if( pChildEffect )
aSelection.push_back( pChildEffect );
}
} while (mxTreeView->iter_next_sibling(*xChild));
}
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.