1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; fill-column: 100 -*- */
3 * This file is part of the LibreOffice project.
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/.
10 #include <uielement/styletoolbarcontroller.hxx>
12 #include <tools/urlobj.hxx>
14 #include <vcl/svapp.hxx>
15 #include <vcl/toolbox.hxx>
16 #include <sal/log.hxx>
17 #include <o3tl/string_view.hxx>
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>
27 OUString
MapFamilyToCommand( std::u16string_view rFamily
)
29 if ( rFamily
== u
"ParagraphStyles" ||
30 rFamily
== u
"CellStyles" || // In sc
31 rFamily
== u
"graphics" ) // In sd
32 return u
".uno:ParaStyle"_ustr
;
33 else if ( rFamily
== u
"CharacterStyles" )
34 return u
".uno:CharStyle"_ustr
;
35 else if ( rFamily
== u
"PageStyles" )
36 return u
".uno:PageStyle"_ustr
;
37 else if ( rFamily
== u
"FrameStyles" ||
38 rFamily
== u
"GraphicStyles" ) // In sc
39 return u
".uno:FrameStyle"_ustr
;
40 else if ( rFamily
== u
"NumberingStyles" )
41 return u
".uno:ListStyle"_ustr
;
42 else if ( rFamily
== u
"TableStyles" )
43 return u
".uno:TableStyle"_ustr
;
48 OUString
GetDisplayFromInternalName( const css::uno::Reference
< css::frame::XFrame
>& rFrame
,
49 const OUString
& rStyleName
,
50 const OUString
& rFamilyName
)
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
);
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
;
66 OUString aDisplayName
;
68 xStyle
->getPropertyValue( u
"DisplayName"_ustr
) >>= aDisplayName
;
71 catch ( const css::uno::Exception
& )
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.
84 StyleDispatcher::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
)
91 SAL_WARN_IF( !m_aCommand
.startsWith( ".uno:StyleApply?" ), "fwk.uielement", "Wrong dispatcher!" );
93 OUString aParams
= rURL
.Arguments
;
94 OUString aStyleName
, aFamilyName
;
98 std::u16string_view aParam
= o3tl::getToken(aParams
, 0, '&', nIndex
);
100 sal_Int32 nParamIndex
= 0;
101 std::u16string_view aParamName
= o3tl::getToken(aParam
, 0, '=', nParamIndex
);
102 if ( nParamIndex
< 0 )
105 if ( aParamName
== u
"Style:string" )
107 std::u16string_view aValue
= o3tl::getToken(aParam
, 0, '=', nParamIndex
);
108 aStyleName
= INetURLObject::decode( aValue
, INetURLObject::DecodeMechanism::WithCharset
);
110 else if ( aParamName
== u
"FamilyName:string" )
112 aFamilyName
= o3tl::getToken(aParam
, 0, '=', nParamIndex
);
115 } while ( nIndex
>= 0 );
117 m_aStatusCommand
= MapFamilyToCommand( aFamilyName
);
118 if ( m_aStatusCommand
.isEmpty() || aStyleName
.isEmpty() )
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
);
126 m_aStyleName
= GetDisplayFromInternalName( rFrame
, aStyleName
, aFamilyName
);
129 css::util::URL aStatusURL
;
130 aStatusURL
.Complete
= u
".uno:StyleApply"_ustr
;
131 m_xUrlTransformer
->parseStrict( aStatusURL
);
132 m_xStyleApplyStatusDispatch
= m_xFrame
->queryDispatch(aStatusURL
, OUString(), 0);
133 aStatusURL
.Complete
= m_aStatusCommand
;
134 m_xUrlTransformer
->parseStrict( aStatusURL
);
135 m_xStyleFamilyStatusDispatch
= m_xFrame
->queryDispatch(aStatusURL
, OUString(), 0);
139 void StyleDispatcher::dispatch( const css::util::URL
& rURL
,
140 const css::uno::Sequence
< css::beans::PropertyValue
>& rArguments
)
142 if ( !m_xFrame
.is() )
145 css::uno::Reference
< css::frame::XDispatch
> xDispatch( m_xFrame
->queryDispatch( rURL
, OUString(), 0 ) );
146 if ( xDispatch
.is() )
147 xDispatch
->dispatch( rURL
, rArguments
);
150 void StyleDispatcher::addStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& rListener
,
151 const css::util::URL
& /*rURL*/ )
153 if ( !m_xOwner
.is() )
154 m_xOwner
.set( rListener
);
155 if (m_xStyleApplyStatusDispatch
)
157 css::util::URL aStatusURL
;
158 aStatusURL
.Complete
= u
".uno:StyleApply"_ustr
;
159 m_xUrlTransformer
->parseStrict(aStatusURL
);
160 m_xStyleApplyStatusDispatch
->addStatusListener(this, aStatusURL
);
162 if (m_xStyleFamilyStatusDispatch
)
164 css::util::URL aStatusURL
;
165 aStatusURL
.Complete
= m_aStatusCommand
;
166 m_xUrlTransformer
->parseStrict( aStatusURL
);
167 m_xStyleFamilyStatusDispatch
->addStatusListener(this, aStatusURL
);
171 void StyleDispatcher::removeStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*rListener*/,
172 const css::util::URL
& /*rURL*/ )
174 if (m_xStyleFamilyStatusDispatch
)
176 css::util::URL aStatusURL
;
177 aStatusURL
.Complete
= m_aStatusCommand
;
178 m_xUrlTransformer
->parseStrict( aStatusURL
);
179 m_xStyleFamilyStatusDispatch
->removeStatusListener(this, aStatusURL
);
181 if (m_xStyleApplyStatusDispatch
)
183 css::util::URL aStatusURL
;
184 aStatusURL
.Complete
= u
".uno:StyleApply"_ustr
;
185 m_xUrlTransformer
->parseStrict(aStatusURL
);
186 m_xStyleApplyStatusDispatch
->removeStatusListener(this, aStatusURL
);
190 void StyleDispatcher::statusChanged( const css::frame::FeatureStateEvent
& rEvent
)
192 if (rEvent
.FeatureURL
.Complete
== ".uno:StyleApply")
194 m_bStyleApplyEnabled
= rEvent
.IsEnabled
;
198 css::frame::status::Template aTemplate
;
199 rEvent
.State
>>= aTemplate
;
201 css::frame::FeatureStateEvent aEvent
;
202 aEvent
.FeatureURL
.Complete
= m_aCommand
;
203 m_xUrlTransformer
->parseStrict( aEvent
.FeatureURL
);
205 aEvent
.IsEnabled
= m_bStyleApplyEnabled
&& rEvent
.IsEnabled
;
206 aEvent
.Requery
= rEvent
.Requery
;
207 aEvent
.State
<<= m_aStyleName
== aTemplate
.StyleName
;
208 m_xOwner
->statusChanged( aEvent
);
211 void StyleDispatcher::disposing( const css::lang::EventObject
& rSource
)
213 if (rSource
.Source
== m_xStyleFamilyStatusDispatch
)
214 m_xStyleFamilyStatusDispatch
.clear();
215 if (rSource
.Source
== m_xStyleApplyStatusDispatch
)
216 m_xStyleApplyStatusDispatch
.clear();
219 StyleToolbarController::StyleToolbarController( const css::uno::Reference
< css::uno::XComponentContext
>& rContext
,
220 const css::uno::Reference
< css::frame::XFrame
>& rFrame
,
221 const OUString
& rCommand
)
222 : ToolboxController( rContext
, rFrame
, rCommand
)
226 void StyleToolbarController::update()
229 throw css::lang::DisposedException();
232 aURL
.Complete
= m_aCommandURL
;
233 m_xUrlTransformer
->parseStrict( aURL
);
235 auto& xDispatcher
= m_aListenerMap
[m_aCommandURL
];
236 if ( xDispatcher
.is() )
237 xDispatcher
->removeStatusListener( this, aURL
);
239 xDispatcher
.set( new StyleDispatcher( m_xFrame
, m_xUrlTransformer
, aURL
) );
240 xDispatcher
->addStatusListener( this, aURL
);
243 void StyleToolbarController::statusChanged( const css::frame::FeatureStateEvent
& rEvent
)
245 SolarMutexGuard aGuard
;
248 throw css::lang::DisposedException();
250 ToolBox
* pToolBox
= nullptr;
251 ToolBoxItemId nItemId
;
252 if ( getToolboxId( nItemId
, &pToolBox
) )
254 bool bChecked
= false;
255 rEvent
.State
>>= bChecked
;
256 pToolBox
->CheckItem( nItemId
, bChecked
);
257 pToolBox
->EnableItem( nItemId
, rEvent
.IsEnabled
);
261 void StyleToolbarController::dispose()
263 ToolboxController::dispose();
264 m_aListenerMap
.clear(); // Break the cycle with StyleDispatcher.
269 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */