/* -*- 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 .
*/
Reference< XInterface > xNormalizedModel( pFormObject->GetUnoControlModel(), UNO_QUERY ); // note that this is normalized (i.e. queried for XInterface explicitly)
::std::pair< MapModelToShape::iterator, bool > aPos =
_rMapping.emplace( xNormalizedModel, pSdrObject );
DBG_ASSERT( aPos.second, "collectShapeModelMapping: model was already existent!" ); // if this asserts, this would mean we have 2 shapes pointing to the same model
}
}
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);
}
if ((pOldShell != pFormShell) || (pOldPage != pNewPage))
{ // new shell during editing if (IsEditingActive())
{
m_xTreeView->end_editing();
m_bEditing = false;
}
m_bDragDataDirty = true; // as a precaution, although I don't drag
}
GetNavModel()->UpdateContent( pFormShell );
// if there is a form, expand root if (m_xRootEntry && !m_xTreeView->get_row_expanded(*m_xRootEntry))
m_xTreeView->expand_row(*m_xRootEntry); // if there is EXACTLY ONE form, expand it too if (m_xRootEntry)
{
std::unique_ptr<weld::TreeIter> xFirst(m_xTreeView->make_iterator(m_xRootEntry.get())); bool bFirst = m_xTreeView->iter_children(*xFirst); if (bFirst)
{
std::unique_ptr<weld::TreeIter> xSibling(m_xTreeView->make_iterator(xFirst.get())); if (!m_xTreeView->iter_next_sibling(*xSibling))
m_xTreeView->expand_row(*xFirst);
}
}
}
// Information for AcceptDrop and Execute Drop
CollectSelectionData(SDI_ALL); if (m_arrCurrentSelection.empty()) // nothing to do returnfalse;
// check whether there are only hidden controls // I may add a format to pCtrlExch bool bHasNonHidden = std::any_of(m_arrCurrentSelection.begin(), m_arrCurrentSelection.end(),
[this](constauto& rEntry) {
FmEntryData* pCurrent = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rEntry)); return !IsHiddenControl( pCurrent );
});
if ( bHasNonHidden && ( 0 == ( _nAction & DND_ACTION_MOVE ) ) ) // non-hidden controls need to be moved returnfalse;
if ( _pHasNonHidden )
*_pHasNonHidden = bHasNonHidden;
IMPL_LINK(NavigatorTree, PopupMenuHdl, const CommandEvent&, rEvt, bool)
{ bool bHandled = false; switch( rEvt.GetCommand() )
{ case CommandEventId::ContextMenu:
{ // Position of click
::Point ptWhere; if (rEvt.IsMouseEvent())
{
ptWhere = rEvt.GetMousePosPixel();
std::unique_ptr<weld::TreeIter> xClickedOn(m_xTreeView->make_iterator()); if (!m_xTreeView->get_dest_row_at_pos(ptWhere, xClickedOn.get(), false)) break; if (!m_xTreeView->is_selected(*xClickedOn))
{
m_xTreeView->unselect_all();
m_xTreeView->select(*xClickedOn);
m_xTreeView->set_cursor(*xClickedOn);
}
} else
{ if (m_arrCurrentSelection.empty()) // only happens with context menu via keyboard break;
std::unique_ptr<weld::TreeIter> xCurrent(m_xTreeView->make_iterator()); if (!m_xTreeView->get_cursor(xCurrent.get())) break;
ptWhere = m_xTreeView->get_row_area(*xCurrent).Center();
}
// update my selection data
CollectSelectionData(SDI_ALL);
// if there is at least one no-root-entry and the root selected, I deselect root if ( (m_arrCurrentSelection.size() > 1) && m_bRootSelected )
{ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
m_xTreeView->set_cursor(*rIter);
m_xTreeView->unselect(*m_xRootEntry);
} bool bSingleSelection = (m_arrCurrentSelection.size() == 1);
DBG_ASSERT( (!m_arrCurrentSelection.empty()) || m_bRootSelected, "no entries selected" ); // shouldn't happen, because I would have selected one during call to IsSelected, // if there was none before
// menu 'New' only exists, if only the root or only one form is selected bool bShowNew = bSingleSelection && (m_nFormsSelected || m_bRootSelected); if (!bShowNew)
xContextMenu->remove(u"new"_ustr);
// 'New'\'Form' under the same terms bool bShowForm = bSingleSelection && (m_nFormsSelected || m_bRootSelected); if (bShowForm)
xSubMenuNew->append(u"form"_ustr, SvxResId(RID_STR_FORM), RID_SVXBMP_FORM);
// 'New'\'hidden...', if exactly one form is selected bool bShowHidden = bSingleSelection && m_nFormsSelected; if (bShowHidden)
xSubMenuNew->append(u"hidden"_ustr, SvxResId(RID_STR_HIDDEN), RID_SVXBMP_HIDDEN);
// 'Delete': everything which is not root can be removed if (m_bRootSelected)
xContextMenu->remove(u"delete"_ustr);
// 'Cut', 'Copy' and 'Paste' bool bShowCut = !m_bRootSelected && implAllowExchange(DND_ACTION_MOVE); if (!bShowCut)
xContextMenu->remove(u"cut"_ustr); bool bShowCopy = !m_bRootSelected && implAllowExchange(DND_ACTION_COPY); if (!bShowCopy)
xContextMenu->remove(u"copy"_ustr); if (!implAcceptPaste())
xContextMenu->remove(u"paste"_ustr);
// TabDialog, if exactly one form bool bShowTabOrder = bSingleSelection && m_nFormsSelected; if (!bShowTabOrder)
xContextMenu->remove(u"taborder"_ustr);
bool bShowProps = true; // in XML forms, we don't allow for the properties of a form // #i36484# if (pFormShell->GetImpl()->isEnhancedForm_Lock() && !m_nControlsSelected)
bShowProps = false; // if the property browser is already open, we don't allow for the properties, too if (pFormShell->GetImpl()->IsPropBrwOpen_Lock())
bShowProps = false;
// and finally, if there's a mixed selection of forms and controls, disable the entry, too if (bShowProps && !pFormShell->GetImpl()->IsPropBrwOpen_Lock())
bShowProps =
(m_nControlsSelected && !m_nFormsSelected) || (!m_nControlsSelected && m_nFormsSelected);
if (!bShowProps)
xContextMenu->remove(u"props"_ustr);
// rename, if one element and no root bool bShowRename = bSingleSelection && !m_bRootSelected; if (!bShowRename)
xContextMenu->remove(u"rename"_ustr);
if (!m_bRootSelected)
{ // Readonly-entry is only for root
xContextMenu->remove(u"designmode"_ustr); // the same for automatic control focus
xContextMenu->remove(u"controlfocus"_ustr);
}
std::unique_ptr<weld::Menu> xConversionMenu(xBuilder->weld_menu(u"changemenu"_ustr)); // ConvertTo-Slots are enabled, if one control is selected // the corresponding slot is disabled if (!m_bRootSelected && !m_nFormsSelected && (m_nControlsSelected == 1))
{
FmXFormShell::GetConversionMenu_Lock(*xConversionMenu); #if OSL_DEBUG_LEVEL > 0 const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
FmControlData* pCurrent = weld::fromId<FmControlData*>(m_xTreeView->get_id(*rIter));
OSL_ENSURE( pFormShell->GetImpl()->isSolelySelected_Lock( pCurrent->GetFormComponent() ), "NavigatorTree::Command: inconsistency between the navigator selection, and the selection as the shell knows it!" ); #endif
pFormModel->BegUndo(aUndoStr); // slot was only available, if there is only one selected entry, // which is a root or a form const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
NewForm(*rIter);
pFormModel->EndUndo();
} elseif (sIdent == "hidden")
{
OUString aStr(SvxResId(RID_STR_CONTROL));
OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERT).replaceAll("#", aStr);
pFormModel->BegUndo(aUndoStr); // slot was valid for (exactly) one selected form const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin();
NewControl(FM_COMPONENT_HIDDEN, *rIter, true);
pFormModel->EndUndo();
} elseif (sIdent == "cut")
doCut(); elseif (sIdent == "copy")
doCopy(); elseif (sIdent == "paste")
doPaste(); elseif (sIdent == "delete")
DeleteSelection(); elseif (sIdent == "taborder")
{ // this slot was effective for exactly one selected form const std::unique_ptr<weld::TreeIter>& rSelectedForm = *m_arrCurrentSelection.begin();
DBG_ASSERT( IsFormEntry(*rSelectedForm), "NavigatorTree::Command: This entry must be a FormEntry." );
if (pSelectHint->IsMixedSelection()) // in this case I deselect all, although the view had a mixed selection // during next selection, I must adapt the navigator to the view
m_bPrevSelectionMixed = true;
}
}
// entry for the data
std::unique_ptr<weld::TreeIter> xEntry = FindEntry(pEntryData); if (!xEntry) return;
// delete entry from TreeListBox // I'm not allowed, to treat the selection, which I trigger: // select changes the MarkList of the view, if somebody else does this at the same time // and removes a selection, we get a problem // e.g. Group controls with open navigator
LockSelectionHandling();
// little problem: I remember the selected data, but if somebody deletes one of these entries, // I get inconsistent... this would be bad
m_xTreeView->unselect(*xEntry);
// selection can be modified during deletion, // but because I disabled SelectionHandling, I have to do it later auto nExpectedSelectionCount = m_xTreeView->count_selected_rows();
bool NavigatorTree::implAcceptPaste( )
{ auto nSelectedEntries = m_xTreeView->count_selected_rows(); if (nSelectedEntries != 1) // no selected entry, or at least two selected entries returnfalse;
// get the clipboard
TransferableDataHelper aClipboardContent(TransferableDataHelper::CreateFromClipboard(m_xTreeView->get_clipboard()));
if ( bHasHiddenControlsFormat )
{ // bHasHiddenControlsFormat means that only hidden controls are part of the data
// hidden controls can be copied to a form only if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0 || !IsFormEntry(*_pTargetEntry)) return DND_ACTION_NONE;
if ( !bSelfSource )
{ // DnD or CnP crossing navigator boundaries // The main problem here is that the current API does not allow us to sneak into the content which // is to be inserted. So we have to allow it for the moment, but maybe reject later on (in the real drop).
// TODO: this smart behaviour later on ... at the moment, we disallow data transfer crossing navigator // boundaries.
return DND_ACTION_NONE;
}
DBG_ASSERT( _bDnD ? m_aControlExchange.isDragSource() : m_aControlExchange.isClipboardOwner(), "NavigatorTree::implAcceptDataTransfer: here only with source=dest!" ); // somebody changed the logic of this method ...
// from here on, I can work with m_aControlExchange instead of _rData!
bool bForeignCollection = m_aControlExchange->getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get(); if ( bForeignCollection )
{ // crossing shell/page boundaries, we can exchange hidden controls only // But if we survived the checks above, we do not have hidden controls. // -> no data transfer
DBG_ASSERT( !bHasHiddenControlsFormat, "NavigatorTree::implAcceptDataTransfer: still hidden controls format!" ); // somebody changed the logic of this method ...
return DND_ACTION_COPY;
}
if (DND_ACTION_MOVE != _nAction) // 'normal' controls within a shell are moved only (never copied) return DND_ACTION_NONE;
if ( m_bDragDataDirty || !bHasDefControlFormat )
{ if (!bHasControlPathFormat) // I am in the shell/page, which has the controls, but I have no format, // which survived the shell change (SVX_FM_CONTROLS_AS_PATH) return DND_ACTION_NONE;
// I must recreate the list of the ExchangeObjects, because the shell was changed during dragging // (there are SvLBoxEntries in it, and we lost them during change)
m_aControlExchange->buildListFromPath(m_xTreeView.get(), m_xRootEntry.get());
m_bDragDataDirty = false;
}
// List of dropped entries from DragServer const ListBoxEntrySet& rDropped = m_aControlExchange->selected();
DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implAcceptDataTransfer: no entries !");
// conditions to disallow the drop // 0) the root entry is part of the list (can't DnD the root!) // 1) one of the dragged entries is to be dropped onto its own parent // 2) - " - is to be dropped onto itself // 3) - " - is a Form and to be dropped onto one of its descendants // 4) one of the entries is a control and to be dropped onto the root // 5) a control or form will be dropped onto a control which is _not_ a sibling (dropping onto a sibling // means moving the control)
// collect the ancestors of the drop target (speeds up 3)
SvLBoxEntrySortedArray arrDropAncestors;
std::unique_ptr<weld::TreeIter> xLoop(m_xTreeView->make_iterator(_pTargetEntry)); do
{
arrDropAncestors.emplace(m_xTreeView->make_iterator(xLoop.get()));
} while (m_xTreeView->iter_parent(*xLoop));
for (constauto& rCurrent : rDropped)
{ // test for 0) if (m_xTreeView->iter_compare(*rCurrent, *m_xRootEntry) == 0) return DND_ACTION_NONE;
// test for 1) if (m_xTreeView->iter_compare(*_pTargetEntry, *xCurrentParent) == 0) return DND_ACTION_NONE;
// test for 2) if (m_xTreeView->iter_compare(*rCurrent, *_pTargetEntry) == 0) return DND_ACTION_NONE;
// test for 5) if (bDropTargetIsComponent) return DND_ACTION_NONE;
// test for 3) if (IsFormEntry(*rCurrent))
{ auto aIter = std::find_if(arrDropAncestors.begin(), arrDropAncestors.end(),
[this, &rCurrent](constauto& rElem) { return m_xTreeView->iter_compare(*rElem, *rCurrent) == 0;
});
if ( aIter != arrDropAncestors.end() ) return DND_ACTION_NONE;
} elseif (IsFormComponentEntry(*rCurrent))
{ // test for 4) if (m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) == 0) return DND_ACTION_NONE;
}
} return DND_ACTION_MOVE;
}
sal_Int8 NavigatorTree::AcceptDrop( const AcceptDropEvent& rEvt )
{
::Point aDropPos = rEvt.maPosPixel;
std::unique_ptr<weld::TreeIter> xDropTarget(m_xTreeView->make_iterator()); // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it if (!m_xTreeView->get_dest_row_at_pos(aDropPos, xDropTarget.get(), false))
xDropTarget.reset(); return implAcceptDataTransfer(m_aDropTargetHelper.GetDataFlavorExVector(), rEvt.mnAction, xDropTarget.get(), true);
}
sal_Int8 NavigatorTree::implExecuteDataTransfer( const OControlTransferData& _rData, sal_Int8 _nAction, const ::Point& _rDropPos, bool _bDnD )
{
std::unique_ptr<weld::TreeIter> xDrop(m_xTreeView->make_iterator()); // get_dest_row_at_pos with false cause we must drop exactly "on" a form to paste a control into it if (!m_xTreeView->get_dest_row_at_pos(_rDropPos, xDrop.get(), false))
xDrop.reset(); return implExecuteDataTransfer( _rData, _nAction, xDrop.get(), _bDnD );
}
if ( DND_ACTION_NONE == implAcceptDataTransfer( rDataFlavors, _nAction, _pTargetEntry, _bDnD ) ) // under some platforms, it may happen that ExecuteDrop is called though AcceptDrop returned DND_ACTION_NONE return DND_ACTION_NONE;
if (!_pTargetEntry) // no target -> no drop return DND_ACTION_NONE;
// format checks #ifdef DBG_UTIL bool bHasHiddenControlsFormat = OControlExchange::hasHiddenControlModelsFormat( rDataFlavors ); bool bForeignCollection = _rData.getFormsRoot().get() != GetNavModel()->GetFormPage()->GetForms().get();
DBG_ASSERT(!bForeignCollection || bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: invalid format (AcceptDrop shouldn't have let this pass) !");
DBG_ASSERT(bForeignCollection || !m_bDragDataDirty, "NavigatorTree::implExecuteDataTransfer: invalid state (shell changed since last exchange resync) !"); // this should be done in AcceptDrop: the list of controls is created in _rData // and m_bDragDataDirty is reset #endif
if ( DND_ACTION_COPY == _nAction )
{ // bHasHiddenControlsFormat means that only hidden controls are part of the data #ifdef DBG_UTIL
DBG_ASSERT( bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: copy allowed for hidden controls only!" ); #endif
DBG_ASSERT( _pTargetEntry && m_xTreeView->iter_compare(*_pTargetEntry, *m_xRootEntry) != 0 && IsFormEntry( *_pTargetEntry ), "NavigatorTree::implExecuteDataTransfer: should not be here!" ); // implAcceptDataTransfer should have caught both cases
#ifdef DBG_UTIL
DBG_ASSERT(bHasHiddenControlsFormat, "NavigatorTree::implExecuteDataTransfer: only copying of hidden controls is supported !"); // should be caught by AcceptDrop #endif
// because i want to select all targets (and only them)
m_xTreeView->unselect_all();
// within undo if (pFormModel)
{
OUString aStr(SvxResId(RID_STR_CONTROL));
OUString aUndoStr = SvxResId(RID_STR_UNDO_CONTAINER_INSERT).replaceAll("#", aStr);
pFormModel->BegUndo(aUndoStr);
}
// copy controls for (sal_Int32 i=0; i<nCount; ++i)
{ // create new control
FmControlData* pNewControlData = NewControl( FM_COMPONENT_HIDDEN, *_pTargetEntry, false);
Reference< XPropertySet > xNewPropSet( pNewControlData->GetPropertySet() );
// copy properties form old control to new one
Reference< XPropertySet > xCurrent(pControls[i], UNO_QUERY); #if (OSL_DEBUG_LEVEL > 0) // check whether it is a hidden control
sal_Int16 nClassId = ::comphelper::getINT16(xCurrent->getPropertyValue(FM_PROP_CLASSID));
OSL_ENSURE(nClassId == FormComponentType::HIDDENCONTROL, "NavigatorTree::implExecuteDataTransfer: invalid control in drop list !"); // if SVX_FM_HIDDEN_CONTROLS-format exists, the sequence // should only contain hidden controls #endif// (OSL_DEBUG_LEVEL > 0)
Reference< XPropertySetInfo > xPropInfo( xCurrent->getPropertySetInfo()); const Sequence< Property> seqAllCurrentProps = xPropInfo->getProperties(); for (Property const & currentProp : seqAllCurrentProps)
{ if (((currentProp.Attributes & PropertyAttribute::READONLY) == 0) && (currentProp.Name != FM_PROP_NAME))
{ // (read-only attribs aren't set, ditto name, // NewControl defined it uniquely
xNewPropSet->setPropertyValue(currentProp.Name, xCurrent->getPropertyValue(currentProp.Name));
}
}
std::unique_ptr<weld::TreeIter> xToSelect = FindEntry(pNewControlData);
m_xTreeView->select(*xToSelect); if (i == 0)
m_xTreeView->set_cursor(*xToSelect);
}
if (pFormModel)
pFormModel->EndUndo();
return _nAction;
}
if ( !OControlExchange::hasFieldExchangeFormat( _rData.GetDataFlavorExVector() ) )
{ // can't do anything without the internal format here ... usually happens when doing DnD or CnP // over navigator boundaries return DND_ACTION_NONE;
}
// some data for the target bool bDropTargetIsForm = IsFormEntry(*_pTargetEntry);
FmFormData* pTargetData = bDropTargetIsForm ? weld::fromId<FmFormData*>(m_xTreeView->get_id(*_pTargetEntry)) : nullptr;
DBG_ASSERT( DND_ACTION_COPY != _nAction, "NavigatorTree::implExecuteDataTransfer: somebody changed the logics!" );
// list of dragged entries const ListBoxEntrySet& rDropped = _rData.selected();
DBG_ASSERT(!rDropped.empty(), "NavigatorTree::implExecuteDataTransfer: no entries!");
// make a copy because rDropped is updated on deleting an entry which we do in the processing loop
ListBoxEntrySet aDropped; for (constauto& rEntry : rDropped)
aDropped.emplace(m_xTreeView->make_iterator(rEntry.get()));
// shell and model
FmFormShell* pFormShell = GetNavModel()->GetFormShell();
FmFormModel* pFormModel = pFormShell ? pFormShell->GetFormModel() : nullptr; if (!pFormModel) return DND_ACTION_NONE;
// for Undo constbool bUndo = pFormModel->IsUndoEnabled();
// remove selection before adding an entry, so the mark doesn't flicker // -> lock action of selection
LockSelectionHandling();
// go through all dropped entries for ( ListBoxEntrySet::const_iterator dropped = aDropped.begin();
dropped != aDropped.end();
++dropped
)
{ bool bFirstEntry = aDropped.begin() == dropped;
// some data of the current element constauto& rCurrent = *dropped;
DBG_ASSERT(rCurrent, "NavigatorTree::implExecuteDataTransfer: invalid entry");
DBG_ASSERT(m_xTreeView->get_iter_depth(*rCurrent) != 0, "NavigatorTree::implExecuteDataTransfer: invalid entry"); // don't drag root
if (xManager.is() && nIndex >= 0)
aEvts = xManager->getScriptEvents(nIndex);
xContainer->removeByIndex(nIndex);
// remove selection
m_xTreeView->unselect(*rCurrent); // and delete it
Remove(pCurrentUserData);
// position in DropParents, where to insert dropped entries if (pTargetData)
xContainer.set(pTargetData->GetElement(), UNO_QUERY); else
xContainer = GetNavModel()->GetForms();
// always insert at the end
nIndex = xContainer->getCount();
// UndoAction for insertion if ( bUndo && GetNavModel()->m_pPropChangeList->CanUndo())
pFormModel->AddUndo(std::make_unique<FmUndoContainerAction>(*pFormModel, FmUndoContainerAction::Inserted,
xContainer, xCurrentChild, nIndex));
// insert in new container if (pTargetData)
{ // insert in a form needs a FormComponent
xContainer->insertByIndex( nIndex,
Any( Reference< XFormComponent >( xCurrentChild, UNO_QUERY ) ) );
} else
{
xContainer->insertByIndex( nIndex,
Any( Reference< XForm >( xCurrentChild, UNO_QUERY ) ) );
}
if (aEvts.hasElements())
{
xManager.set(xContainer, UNO_QUERY); if (xManager.is())
xManager->registerScriptEvents(nIndex, aEvts);
}
GetNavModel()->m_pPropChangeList->UnLock();
// give an entry the new parent
pCurrentUserData->SetParent(pTargetData);
// give parent the new child if (pTargetData)
pTargetData->GetChildList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex ); else
GetNavModel()->GetRootList()->insert( std::unique_ptr<FmEntryData>(pCurrentUserData), nIndex );
// announce to myself and reselect
std::unique_ptr<weld::TreeIter> xNew = Insert( pCurrentUserData, nIndex ); if (bFirstEntry && xNew)
{ if (m_xTreeView->iter_parent(*xNew))
m_xTreeView->expand_row(*xNew);
}
}
UnlockSelectionHandling();
if( bUndo )
pFormModel->EndUndo();
// During the move, the markings of the underlying view did not change (because the view is not affected by the logical // hierarchy of the form/control models. But my selection changed - which means I have to adjust it according to the // view marks, again.
SynchronizeSelection();
// in addition, with the move of controls such things as "the current form" may have changed - force the shell // to update itself accordingly if( pFormShell && pFormShell->GetImpl() && pFormShell->GetFormView() )
pFormShell->GetImpl()->DetermineSelection_Lock( pFormShell->GetFormView()->GetMarkedObjectList() );
void NavigatorTree::ModelHasRemoved(const weld::TreeIter* pTypedEntry)
{ if (doingKeyboardCut())
{ auto aIter = std::find_if(m_aCutEntries.begin(), m_aCutEntries.end(),
[this, pTypedEntry](constauto& rElem) { return m_xTreeView->iter_compare(*rElem, *pTypedEntry) == 0;
}); if (aIter != m_aCutEntries.end())
m_aCutEntries.erase(aIter);
}
if (m_aControlExchange.isDataExchangeActive())
{ if (0 == m_aControlExchange->onEntryRemoved(m_xTreeView.get(), pTypedEntry))
{ // last of the entries which we put into the clipboard has been deleted from the tree. // Give up the clipboard ownership.
m_aControlExchange.clear();
}
}
}
void NavigatorTree::doCut()
{ if ( !implPrepareExchange( DND_ACTION_MOVE ) ) return;
// mark all the entries we just "cut" into the clipboard as "nearly moved" for (constauto& rEntry : m_arrCurrentSelection )
{ if (!rEntry) continue;
m_aCutEntries.emplace(m_xTreeView->make_iterator(rEntry.get()));
m_xTreeView->set_sensitive(*rEntry, false);
}
}
// create new form const Reference<XComponentContext>& xContext = comphelper::getProcessComponentContext();
Reference< XForm > xNewForm(xContext->getServiceManager()->createInstanceWithContext(FM_SUN_COMPONENT_FORM, xContext), UNO_QUERY); if (!xNewForm.is()) return;
Reference< XPropertySet > xPropertySet(xNewForm, UNO_QUERY); if (!xPropertySet.is()) return;
FmFormData* pNewFormData = new FmFormData(xNewForm, pParentFormData);
// set name
OUString aName = GenerateName(*pNewFormData);
pNewFormData->SetText(aName);
try
{
xPropertySet->setPropertyValue( FM_PROP_NAME, Any(aName) ); // a form should always have the command type table as default
xPropertySet->setPropertyValue( FM_PROP_COMMANDTYPE, Any(sal_Int32(CommandType::TABLE)));
} catch ( const Exception& )
{
OSL_FAIL("NavigatorTree::NewForm : could not set essential properties!");
}
// insert form
GetNavModel()->Insert(pNewFormData, SAL_MAX_UINT32, true);
// set new form as active
FmFormShell* pFormShell = GetNavModel()->GetFormShell(); if( pFormShell )
{
InterfaceBag aSelection;
aSelection.insert( Reference<XInterface>( xNewForm, UNO_QUERY ) );
pFormShell->GetImpl()->setCurrentSelection_Lock(std::move(aSelection));
IMPL_LINK_NOARG(NavigatorTree, OnClipboardAction, OLocalExchange&, void)
{ if ( m_aControlExchange.isClipboardOwner() ) return;
if ( !doingKeyboardCut() ) return;
for (constauto& rEntry : m_aCutEntries)
{ if (!rEntry) continue;
m_xTreeView->set_sensitive(*rEntry, true);
}
ListBoxEntrySet().swap(m_aCutEntries);
m_bKeyboardCut = false;
}
void NavigatorTree::ShowSelectionProperties(bool bForce)
{ // at first i need the FormShell
FmFormShell* pFormShell = GetNavModel()->GetFormShell(); if (!pFormShell) // no shell -> impossible to set curObject -> leave return;
CollectSelectionData(SDI_ALL);
SAL_WARN_IF(static_cast<size_t>(m_nFormsSelected + m_nControlsSelected
+ (m_bRootSelected ? 1 : 0)) != m_arrCurrentSelection.size(), "svx.form", "NavigatorTree::ShowSelectionProperties : selection meta data invalid !");
if (m_bRootSelected)
; // no properties for the root, neither for single nor for multi selection elseif ( m_nFormsSelected + m_nControlsSelected == 0 ) // none of the two should be less 0
; // no selection -> no properties elseif ( m_nFormsSelected * m_nControlsSelected != 0 )
; // mixed selection -> no properties else
{ // either only forms, or only controls are selected if (m_arrCurrentSelection.size() == 1)
{ const std::unique_ptr<weld::TreeIter>& rIter = *m_arrCurrentSelection.begin(); if (m_nFormsSelected > 0)
{ // exactly one form is selected
FmFormData* pFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(*rIter));
aSelection.insert( Reference< XInterface >( pFormData->GetFormIface(), UNO_QUERY ) );
} else
{ // exactly one control is selected (whatever hidden or normal)
FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rIter));
aSelection.insert( Reference< XInterface >( pEntryData->GetElement(), UNO_QUERY ) );
}
} else
{ // it's a MultiSelection, so we must build a MultiSet if (m_nFormsSelected > 0)
{ // ... only forms // first of all collect PropertySet-Interfaces of the forms
SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin(); for ( sal_Int32 i = 0; i < m_nFormsSelected; ++i )
{ const std::unique_ptr<weld::TreeIter>& rIter = *it;
FmFormData* pFormData = weld::fromId<FmFormData*>(m_xTreeView->get_id(*rIter));
aSelection.insert( pFormData->GetPropertySet() );
++it;
}
} else
{ // ... only controls if (m_nHiddenControls == m_nControlsSelected)
{ // a MultiSet for properties of hidden controls
SvLBoxEntrySortedArray::const_iterator it = m_arrCurrentSelection.begin(); for ( sal_Int32 i = 0; i < m_nHiddenControls; ++i )
{ const std::unique_ptr<weld::TreeIter>& rIter = *it;
FmEntryData* pEntryData = weld::fromId<FmEntryData*>(m_xTreeView->get_id(*rIter));
aSelection.insert( pEntryData->GetPropertySet() );
++it;
}
} elseif (m_nHiddenControls == 0)
{ // only normal controls
bSetSelectionAsMarkList = true;
}
}
}
}
// and now my form and my SelObject if ( bSetSelectionAsMarkList )
pFormShell->GetImpl()->setCurrentSelectionFromMark_Lock(pFormShell->GetFormView()->GetMarkedObjectList()); else
pFormShell->GetImpl()->setCurrentSelection_Lock(std::move(aSelection));
if (pFormShell->GetImpl()->IsPropBrwOpen_Lock() || bForce)
{ // and now deliver all to the PropertyBrowser
pFormShell->GetViewShell()->GetViewFrame().GetDispatcher()->Execute( SID_FM_SHOW_PROPERTY_BROWSER, SfxCallMode::ASYNCHRON );
}
}
void NavigatorTree::DeleteSelection()
{ // of course, i can't delete root bool bRootSelected = m_xTreeView->is_selected(*m_xRootEntry); auto nSelectedEntries = m_xTreeView->count_selected_rows();
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.23 Sekunden
(vorverarbeitet)
¤
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.