LibreOffice Module framework (master) 1
styletoolbarcontroller.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
11
12#include <tools/urlobj.hxx>
13#include <utility>
14#include <vcl/svapp.hxx>
15#include <vcl/toolbox.hxx>
16#include <sal/log.hxx>
17#include <o3tl/string_view.hxx>
18
19#include <com/sun/star/frame/XController.hpp>
20#include <com/sun/star/frame/status/Template.hpp>
21#include <com/sun/star/lang/DisposedException.hpp>
22#include <com/sun/star/style/XStyleFamiliesSupplier.hpp>
23#include <com/sun/star/util/XURLTransformer.hpp>
24
25namespace {
26
27OUString MapFamilyToCommand( std::u16string_view rFamily )
28{
29 if ( rFamily == u"ParagraphStyles" ||
30 rFamily == u"CellStyles" || // In sc
31 rFamily == u"graphics" ) // In sd
32 return ".uno:ParaStyle";
33 else if ( rFamily == u"CharacterStyles" )
34 return ".uno:CharStyle";
35 else if ( rFamily == u"PageStyles" )
36 return ".uno:PageStyle";
37 else if ( rFamily == u"FrameStyles" ||
38 rFamily == u"GraphicStyles" ) // In sc
39 return ".uno:FrameStyle";
40 else if ( rFamily == u"NumberingStyles" )
41 return ".uno:ListStyle";
42 else if ( rFamily == u"TableStyles" )
43 return ".uno:TableStyle";
44
45 return OUString();
46}
47
48OUString GetDisplayFromInternalName( const css::uno::Reference< css::frame::XFrame >& rFrame,
49 const OUString& rStyleName,
50 const OUString& rFamilyName )
51{
52 try
53 {
54 css::uno::Reference< css::frame::XController > xController(
55 rFrame->getController(), css::uno::UNO_SET_THROW );
56 css::uno::Reference< css::style::XStyleFamiliesSupplier > xStylesSupplier(
57 xController->getModel(), css::uno::UNO_QUERY_THROW );
58 css::uno::Reference< css::container::XNameAccess > xFamilies(
59 xStylesSupplier->getStyleFamilies(), css::uno::UNO_SET_THROW );
60
61 css::uno::Reference< css::container::XNameAccess > xStyleSet;
62 xFamilies->getByName( rFamilyName ) >>= xStyleSet;
63 css::uno::Reference< css::beans::XPropertySet > xStyle;
64 xStyleSet->getByName( rStyleName ) >>= xStyle;
65
66 OUString aDisplayName;
67 if ( xStyle.is() )
68 xStyle->getPropertyValue( "DisplayName" ) >>= aDisplayName;
69 return aDisplayName;
70 }
71 catch ( const css::uno::Exception& )
72 {
73 // We couldn't get the display name. As a last resort we'll
74 // try to use the internal name, as was specified in the URL.
75 }
76
77 return rStyleName;
78}
79
80}
81
82namespace framework {
83
84StyleDispatcher::StyleDispatcher( const css::uno::Reference< css::frame::XFrame >& rFrame,
85 css::uno::Reference< css::util::XURLTransformer > xUrlTransformer,
86 const css::util::URL& rURL )
87 : m_aCommand( rURL.Complete )
88 , m_xUrlTransformer(std::move( xUrlTransformer ))
89 , m_xFrame( rFrame, css::uno::UNO_QUERY )
90{
91 SAL_WARN_IF( !m_aCommand.startsWith( ".uno:StyleApply?" ), "fwk.uielement", "Wrong dispatcher!" );
92
93 OUString aParams = rURL.Arguments;
94 OUString aStyleName, aFamilyName;
95 sal_Int32 nIndex = 0;
96 do
97 {
98 std::u16string_view aParam = o3tl::getToken(aParams, 0, '&', nIndex );
99
100 sal_Int32 nParamIndex = 0;
101 std::u16string_view aParamName = o3tl::getToken(aParam, 0, '=', nParamIndex );
102 if ( nParamIndex < 0 )
103 break;
104
105 if ( aParamName == u"Style:string" )
106 {
107 std::u16string_view aValue = o3tl::getToken(aParam, 0, '=', nParamIndex );
109 }
110 else if ( aParamName == u"FamilyName:string" )
111 {
112 aFamilyName = o3tl::getToken(aParam, 0, '=', nParamIndex );
113 }
114
115 } while ( nIndex >= 0 );
116
117 m_aStatusCommand = MapFamilyToCommand( aFamilyName );
118 if ( m_aStatusCommand.isEmpty() || aStyleName.isEmpty() )
119 {
120 // We can't provide status updates for this command, but just executing
121 // the command should still work (given that the command is valid).
122 SAL_WARN( "fwk.uielement", "Unable to parse as a style command: " << m_aCommand );
123 return;
124 }
125
126 m_aStyleName = GetDisplayFromInternalName( rFrame, aStyleName, aFamilyName );
127 if ( m_xFrame.is() )
128 {
129 css::util::URL aStatusURL;
130 aStatusURL.Complete = m_aStatusCommand;
131 m_xUrlTransformer->parseStrict( aStatusURL );
132 m_xStatusDispatch = m_xFrame->queryDispatch( aStatusURL, OUString(), 0 );
133 }
134}
135
136void StyleDispatcher::dispatch( const css::util::URL& rURL,
137 const css::uno::Sequence< css::beans::PropertyValue >& rArguments )
138{
139 if ( !m_xFrame.is() )
140 return;
141
142 css::uno::Reference< css::frame::XDispatch > xDispatch( m_xFrame->queryDispatch( rURL, OUString(), 0 ) );
143 if ( xDispatch.is() )
144 xDispatch->dispatch( rURL, rArguments );
145}
146
147void StyleDispatcher::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& rListener,
148 const css::util::URL& /*rURL*/ )
149{
150 if ( m_xStatusDispatch.is() )
151 {
152 if ( !m_xOwner.is() )
153 m_xOwner.set( rListener );
154
155 css::util::URL aStatusURL;
156 aStatusURL.Complete = m_aStatusCommand;
157 m_xUrlTransformer->parseStrict( aStatusURL );
158 m_xStatusDispatch->addStatusListener( this, aStatusURL );
159 }
160}
161
162void StyleDispatcher::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*rListener*/,
163 const css::util::URL& /*rURL*/ )
164{
165 if ( m_xStatusDispatch.is() )
166 {
167 css::util::URL aStatusURL;
168 aStatusURL.Complete = m_aStatusCommand;
169 m_xUrlTransformer->parseStrict( aStatusURL );
170 m_xStatusDispatch->removeStatusListener( this, aStatusURL );
171 }
172}
173
174void StyleDispatcher::statusChanged( const css::frame::FeatureStateEvent& rEvent )
175{
176 css::frame::status::Template aTemplate;
177 rEvent.State >>= aTemplate;
178
179 css::frame::FeatureStateEvent aEvent;
180 aEvent.FeatureURL.Complete = m_aCommand;
181 m_xUrlTransformer->parseStrict( aEvent.FeatureURL );
182
183 aEvent.IsEnabled = rEvent.IsEnabled;
184 aEvent.Requery = rEvent.Requery;
185 aEvent.State <<= m_aStyleName == aTemplate.StyleName;
186 m_xOwner->statusChanged( aEvent );
187}
188
189void StyleDispatcher::disposing( const css::lang::EventObject& /*rSource*/ )
190{
191 m_xStatusDispatch.clear();
192}
193
194StyleToolbarController::StyleToolbarController( const css::uno::Reference< css::uno::XComponentContext >& rContext,
195 const css::uno::Reference< css::frame::XFrame >& rFrame,
196 const OUString& rCommand )
197 : ToolboxController( rContext, rFrame, rCommand )
198{
199}
200
202{
203 if ( m_bDisposed )
204 throw css::lang::DisposedException();
205
206 css::util::URL aURL;
207 aURL.Complete = m_aCommandURL;
208 m_xUrlTransformer->parseStrict( aURL );
209
210 auto& xDispatcher = m_aListenerMap[m_aCommandURL];
211 if ( xDispatcher.is() )
212 xDispatcher->removeStatusListener( this, aURL );
213
214 xDispatcher.set( new StyleDispatcher( m_xFrame, m_xUrlTransformer, aURL ) );
215 xDispatcher->addStatusListener( this, aURL );
216}
217
218void StyleToolbarController::statusChanged( const css::frame::FeatureStateEvent& rEvent )
219{
220 SolarMutexGuard aGuard;
221
222 if ( m_bDisposed )
223 throw css::lang::DisposedException();
224
225 ToolBox* pToolBox = nullptr;
226 ToolBoxItemId nItemId;
227 if ( getToolboxId( nItemId, &pToolBox ) )
228 {
229 bool bChecked = false;
230 rEvent.State >>= bChecked;
231 pToolBox->CheckItem( nItemId, bChecked );
232 pToolBox->EnableItem( nItemId, rEvent.IsEnabled );
233 }
234}
235
237{
238 ToolboxController::dispose();
239 m_aListenerMap.clear(); // Break the cycle with StyleDispatcher.
240}
241
242}
243
244/* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
css::uno::Reference< css::lang::XComponent > m_xFrame
AnyEventRef aEvent
static OUString decode(std::u16string_view rText, DecodeMechanism eMechanism, rtl_TextEncoding eCharset=RTL_TEXTENCODING_UTF8)
void EnableItem(ToolBoxItemId nItemId, bool bEnable=true)
void CheckItem(ToolBoxItemId nItemId, bool bCheck=true)
A dispatcher that serves as a proxy for style commands with arguments i.e.
css::uno::Reference< css::util::XURLTransformer > m_xUrlTransformer
css::uno::Reference< css::frame::XStatusListener > m_xOwner
css::uno::Reference< css::frame::XDispatchProvider > m_xFrame
void SAL_CALL dispatch(const css::util::URL &rURL, const css::uno::Sequence< css::beans::PropertyValue > &rArguments) override
void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &rEvent) override
void SAL_CALL disposing(const css::lang::EventObject &rSource) override
void SAL_CALL addStatusListener(const css::uno::Reference< css::frame::XStatusListener > &rListener, const css::util::URL &rURL) override
void SAL_CALL removeStatusListener(const css::uno::Reference< css::frame::XStatusListener > &rListener, const css::util::URL &rURL) override
css::uno::Reference< css::frame::XDispatch > m_xStatusDispatch
StyleDispatcher(const css::uno::Reference< css::frame::XFrame > &rFrame, css::uno::Reference< css::util::XURLTransformer > xUrlTransformer, const css::util::URL &rURL)
StyleToolbarController(const css::uno::Reference< css::uno::XComponentContext > &rContext, const css::uno::Reference< css::frame::XFrame > &rFrame, const OUString &rCommand)
void SAL_CALL statusChanged(const css::frame::FeatureStateEvent &rEvent) override
URLToDispatchMap m_aListenerMap
css::uno::Reference< css::util::XURLTransformer > m_xUrlTransformer
bool getToolboxId(ToolBoxItemId &rItemId, ToolBox **ppToolBox)
css::uno::Reference< css::frame::XFrame > m_xFrame
Reference< XDispatch > xDispatch
URL aURL
float u
sal_Int32 nIndex
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
std::basic_string_view< charT, traits > getToken(std::basic_string_view< charT, traits > sv, charT delimiter, std::size_t &position)
Reference< XController > xController