diff options
Diffstat (limited to 'chart2/source/controller/main/ElementSelector.cxx')
-rw-r--r-- | chart2/source/controller/main/ElementSelector.cxx | 319 |
1 files changed, 319 insertions, 0 deletions
diff --git a/chart2/source/controller/main/ElementSelector.cxx b/chart2/source/controller/main/ElementSelector.cxx new file mode 100644 index 000000000..d538108ae --- /dev/null +++ b/chart2/source/controller/main/ElementSelector.cxx @@ -0,0 +1,319 @@ +/* -*- 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 "ElementSelector.hxx" +#include <ObjectNameProvider.hxx> +#include <ObjectHierarchy.hxx> +#include <servicenames.hxx> +#include <DrawViewWrapper.hxx> +#include <ResId.hxx> +#include <strings.hrc> +#include <ObjectIdentifier.hxx> +#include <ChartController.hxx> +#include <ChartModel.hxx> + +#include <cppuhelper/supportsservice.hxx> +#include <o3tl/safeint.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/svapp.hxx> + +namespace chart { class ExplicitValueProvider; } + +namespace chart +{ + +using namespace com::sun::star; +using namespace com::sun::star::uno; +using ::com::sun::star::uno::Any; +using ::com::sun::star::uno::Reference; +using ::com::sun::star::uno::Sequence; + +namespace +{ +constexpr OUStringLiteral lcl_aServiceName + = u"com.sun.star.comp.chart.ElementSelectorToolbarController"; +} + +SelectorListBox::SelectorListBox(vcl::Window* pParent) + : InterimItemWindow(pParent, "modules/schart/ui/combobox.ui", "ComboBox") + , m_xWidget(m_xBuilder->weld_combo_box("combobox")) + , m_bReleaseFocus(true) +{ + InitControlBase(m_xWidget.get()); + + m_xWidget->connect_key_press(LINK(this, SelectorListBox, KeyInputHdl)); + m_xWidget->connect_changed(LINK(this, SelectorListBox, SelectHdl)); + m_xWidget->connect_focus_out(LINK(this, SelectorListBox, FocusOutHdl)); + + ::Size aLogicalSize(75, 0); + ::Size aPixelSize = LogicToPixel(aLogicalSize, MapMode(MapUnit::MapAppFont)); + m_xWidget->set_size_request(aPixelSize.Width(), -1); + SetSizePixel(m_xContainer->get_preferred_size()); +} + +void SelectorListBox::dispose() +{ + m_xWidget.reset(); + InterimItemWindow::dispose(); +} + +SelectorListBox::~SelectorListBox() +{ + disposeOnce(); +} + +static void lcl_addObjectsToList( const ObjectHierarchy& rHierarchy, const ObjectIdentifier & rParent, std::vector< ListBoxEntryData >& rEntries + , const sal_Int32 nHierarchyDepth, const rtl::Reference<::chart::ChartModel>& xChartDoc ) +{ + ObjectHierarchy::tChildContainer aChildren( rHierarchy.getChildren(rParent) ); + for (auto const& child : aChildren) + { + ListBoxEntryData aEntry; + aEntry.OID = child; + aEntry.UIName = ObjectNameProvider::getNameForCID( child.getObjectCID(), xChartDoc ); + aEntry.nHierarchyDepth = nHierarchyDepth; + rEntries.push_back(aEntry); + lcl_addObjectsToList( rHierarchy, child, rEntries, nHierarchyDepth+1, xChartDoc ); + } +} + +void SelectorListBox::SetChartController( const rtl::Reference< ::chart::ChartController >& xChartController ) +{ + m_xChartController = xChartController.get(); +} + +void SelectorListBox::UpdateChartElementsListAndSelection() +{ + m_xWidget->clear(); + m_aEntries.clear(); + + rtl::Reference< ::chart::ChartController > xChartController = m_xChartController.get(); + if( xChartController.is() ) + { + ObjectIdentifier aSelectedOID( xChartController->getSelection() ); + OUString aSelectedCID = aSelectedOID.getObjectCID(); + + rtl::Reference<::chart::ChartModel> xChartDoc = xChartController->getChartModel(); + ObjectType eType( aSelectedOID.getObjectType() ); + bool bAddSelectionToList = false; + if ( eType == OBJECTTYPE_DATA_POINT || eType == OBJECTTYPE_DATA_LABEL || eType == OBJECTTYPE_SHAPE ) + bAddSelectionToList = true; + + Reference< uno::XInterface > xChartView; + rtl::Reference< ChartModel > xFact = xChartController->getChartModel(); + if( xFact.is() ) + xChartView = xFact->createInstance( CHART_VIEW_SERVICE_NAME ); + ExplicitValueProvider* pExplicitValueProvider = nullptr; //ExplicitValueProvider::getExplicitValueProvider(xChartView); this creates all visible data points, that's too much + ObjectHierarchy aHierarchy( xChartDoc, pExplicitValueProvider, true /*bFlattenDiagram*/, true /*bOrderingForElementSelector*/ ); + lcl_addObjectsToList( aHierarchy, ::chart::ObjectHierarchy::getRootNodeOID(), m_aEntries, 0, xChartDoc ); + + if( bAddSelectionToList ) + { + if ( aSelectedOID.isAutoGeneratedObject() ) + { + OUString aSeriesCID = ObjectIdentifier::createClassifiedIdentifierForParticle( ObjectIdentifier::getSeriesParticleFromCID( aSelectedCID ) ); + std::vector< ListBoxEntryData >::iterator aIt = std::find_if(m_aEntries.begin(), m_aEntries.end(), + [&aSeriesCID](const ListBoxEntryData& rEntry) { return rEntry.OID.getObjectCID().match(aSeriesCID); }); + if (aIt != m_aEntries.end()) + { + ListBoxEntryData aEntry; + aEntry.UIName = ObjectNameProvider::getNameForCID( aSelectedCID, xChartDoc ); + aEntry.OID = aSelectedOID; + ++aIt; + if( aIt != m_aEntries.end() ) + m_aEntries.insert(aIt, aEntry); + else + m_aEntries.push_back( aEntry ); + } + } + else if ( aSelectedOID.isAdditionalShape() ) + { + ListBoxEntryData aEntry; + SdrObject* pSelectedObj = DrawViewWrapper::getSdrObject( aSelectedOID.getAdditionalShape() ); + OUString aName = pSelectedObj ? pSelectedObj->GetName() : OUString(); + aEntry.UIName = ( aName.isEmpty() ? SchResId( STR_OBJECT_SHAPE ) : aName ); + aEntry.OID = aSelectedOID; + m_aEntries.push_back( aEntry ); + } + } + + m_xWidget->freeze(); + sal_uInt16 nEntryPosToSelect = 0; bool bSelectionFound = false; + sal_uInt16 nN=0; + for (auto const& entry : m_aEntries) + { + // tdf#152087 strip any newlines from the entry + m_xWidget->append_text(entry.UIName.replaceAll("\n", " ")); + if ( !bSelectionFound && aSelectedOID == entry.OID ) + { + nEntryPosToSelect = nN; + bSelectionFound = true; + } + ++nN; + } + m_xWidget->thaw(); + + if( bSelectionFound ) + m_xWidget->set_active(nEntryPosToSelect); + } + m_xWidget->save_value(); //remind current selection pos +} + +void SelectorListBox::ReleaseFocus_Impl() +{ + if ( !m_bReleaseFocus ) + { + m_bReleaseFocus = true; + return; + } + + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + Reference< frame::XFrame > xFrame( xController->getFrame() ); + if ( xFrame.is() && xFrame->getContainerWindow().is() ) + xFrame->getContainerWindow()->setFocus(); +} + +IMPL_LINK(SelectorListBox, SelectHdl, weld::ComboBox&, rComboBox, void) +{ + if (rComboBox.changed_by_direct_pick()) + { + const sal_Int32 nPos = rComboBox.get_active(); + if (o3tl::make_unsigned(nPos) < m_aEntries.size()) + { + ObjectIdentifier aOID = m_aEntries[nPos].OID; + rtl::Reference< ::chart::ChartController > xController = m_xChartController.get(); + if( xController.is() ) + xController->select( aOID.getAny() ); + } + ReleaseFocus_Impl(); + } +} + +IMPL_LINK(SelectorListBox, KeyInputHdl, const KeyEvent&, rKEvt, bool) +{ + bool bHandled = false; + + sal_uInt16 nCode = rKEvt.GetKeyCode().GetCode(); + + switch ( nCode ) + { + case KEY_RETURN: + case KEY_TAB: + { + if ( nCode == KEY_TAB ) + m_bReleaseFocus = false; + else + bHandled = true; + SelectHdl(*m_xWidget); + break; + } + + case KEY_ESCAPE: + m_xWidget->set_active_text(m_xWidget->get_saved_value()); //restore saved selection + ReleaseFocus_Impl(); + break; + } + + return bHandled || ChildKeyInput(rKEvt); +} + +IMPL_LINK_NOARG(SelectorListBox, FocusOutHdl, weld::Widget&, void) +{ + if (m_xWidget && !m_xWidget->has_focus()) // comboboxes can be comprised of multiple widgets, ensure all have lost focus + m_xWidget->set_active_text(m_xWidget->get_saved_value()); +} + +OUString SAL_CALL ElementSelectorToolbarController::getImplementationName() +{ + return lcl_aServiceName; +} + +sal_Bool SAL_CALL ElementSelectorToolbarController::supportsService( const OUString& rServiceName ) +{ + return cppu::supportsService(this, rServiceName); +} + +css::uno::Sequence< OUString > SAL_CALL ElementSelectorToolbarController::getSupportedServiceNames() +{ + return { "com.sun.star.frame.ToolbarController" }; +} +ElementSelectorToolbarController::ElementSelectorToolbarController() +{ +} +ElementSelectorToolbarController::~ElementSelectorToolbarController() +{ +} +// XInterface +Any SAL_CALL ElementSelectorToolbarController::queryInterface( const Type& _rType ) +{ + Any aReturn = ToolboxController::queryInterface(_rType); + if (!aReturn.hasValue()) + aReturn = ElementSelectorToolbarController_BASE::queryInterface(_rType); + return aReturn; +} +void SAL_CALL ElementSelectorToolbarController::acquire() noexcept +{ + ToolboxController::acquire(); +} +void SAL_CALL ElementSelectorToolbarController::release() noexcept +{ + ToolboxController::release(); +} +void SAL_CALL ElementSelectorToolbarController::statusChanged( const frame::FeatureStateEvent& rEvent ) +{ + if( m_apSelectorListBox ) + { + SolarMutexGuard aSolarMutexGuard; + if ( rEvent.FeatureURL.Path == "ChartElementSelector" ) + { + Reference< frame::XController > xChartController; + rEvent.State >>= xChartController; + ::chart::ChartController* pController = dynamic_cast<::chart::ChartController*>(xChartController.get()); + assert(!xChartController || pController); + m_apSelectorListBox->SetChartController( pController ); + m_apSelectorListBox->UpdateChartElementsListAndSelection(); + } + } +} +uno::Reference< awt::XWindow > SAL_CALL ElementSelectorToolbarController::createItemWindow( const uno::Reference< awt::XWindow >& xParent ) +{ + uno::Reference< awt::XWindow > xItemWindow; + if( !m_apSelectorListBox ) + { + VclPtr<vcl::Window> pParent = VCLUnoHelper::GetWindow( xParent ); + if( pParent ) + { + m_apSelectorListBox.reset(VclPtr<SelectorListBox>::Create(pParent)); + } + } + if( m_apSelectorListBox ) + xItemWindow = VCLUnoHelper::GetInterface( m_apSelectorListBox.get() ); + return xItemWindow; +} + +} // chart2 + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface * +com_sun_star_comp_chart_ElementSelectorToolbarController_get_implementation(css::uno::XComponentContext *, + css::uno::Sequence<css::uno::Any> const &) +{ + return cppu::acquire(new chart::ElementSelectorToolbarController ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |