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 ".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";
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( "DisplayName" ) >>= 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
= m_aStatusCommand
;
131 m_xUrlTransformer
->parseStrict( aStatusURL
);
132 m_xStatusDispatch
= m_xFrame
->queryDispatch( aStatusURL
, OUString(), 0 );
136 void StyleDispatcher::dispatch( const css::util::URL
& rURL
,
137 const css::uno::Sequence
< css::beans::PropertyValue
>& rArguments
)
139 if ( !m_xFrame
.is() )
142 css::uno::Reference
< css::frame::XDispatch
> xDispatch( m_xFrame
->queryDispatch( rURL
, OUString(), 0 ) );
143 if ( xDispatch
.is() )
144 xDispatch
->dispatch( rURL
, rArguments
);
147 void StyleDispatcher::addStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& rListener
,
148 const css::util::URL
& /*rURL*/ )
150 if ( m_xStatusDispatch
.is() )
152 if ( !m_xOwner
.is() )
153 m_xOwner
.set( rListener
);
155 css::util::URL aStatusURL
;
156 aStatusURL
.Complete
= m_aStatusCommand
;
157 m_xUrlTransformer
->parseStrict( aStatusURL
);
158 m_xStatusDispatch
->addStatusListener( this, aStatusURL
);
162 void StyleDispatcher::removeStatusListener( const css::uno::Reference
< css::frame::XStatusListener
>& /*rListener*/,
163 const css::util::URL
& /*rURL*/ )
165 if ( m_xStatusDispatch
.is() )
167 css::util::URL aStatusURL
;
168 aStatusURL
.Complete
= m_aStatusCommand
;
169 m_xUrlTransformer
->parseStrict( aStatusURL
);
170 m_xStatusDispatch
->removeStatusListener( this, aStatusURL
);
174 void StyleDispatcher::statusChanged( const css::frame::FeatureStateEvent
& rEvent
)
176 css::frame::status::Template aTemplate
;
177 rEvent
.State
>>= aTemplate
;
179 css::frame::FeatureStateEvent aEvent
;
180 aEvent
.FeatureURL
.Complete
= m_aCommand
;
181 m_xUrlTransformer
->parseStrict( aEvent
.FeatureURL
);
183 aEvent
.IsEnabled
= rEvent
.IsEnabled
;
184 aEvent
.Requery
= rEvent
.Requery
;
185 aEvent
.State
<<= m_aStyleName
== aTemplate
.StyleName
;
186 m_xOwner
->statusChanged( aEvent
);
189 void StyleDispatcher::disposing( const css::lang::EventObject
& /*rSource*/ )
191 m_xStatusDispatch
.clear();
194 StyleToolbarController::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
)
201 void StyleToolbarController::update()
204 throw css::lang::DisposedException();
207 aURL
.Complete
= m_aCommandURL
;
208 m_xUrlTransformer
->parseStrict( aURL
);
210 auto& xDispatcher
= m_aListenerMap
[m_aCommandURL
];
211 if ( xDispatcher
.is() )
212 xDispatcher
->removeStatusListener( this, aURL
);
214 xDispatcher
.set( new StyleDispatcher( m_xFrame
, m_xUrlTransformer
, aURL
) );
215 xDispatcher
->addStatusListener( this, aURL
);
218 void StyleToolbarController::statusChanged( const css::frame::FeatureStateEvent
& rEvent
)
220 SolarMutexGuard aGuard
;
223 throw css::lang::DisposedException();
225 ToolBox
* pToolBox
= nullptr;
226 ToolBoxItemId nItemId
;
227 if ( getToolboxId( nItemId
, &pToolBox
) )
229 bool bChecked
= false;
230 rEvent
.State
>>= bChecked
;
231 pToolBox
->CheckItem( nItemId
, bChecked
);
232 pToolBox
->EnableItem( nItemId
, rEvent
.IsEnabled
);
236 void StyleToolbarController::dispose()
238 ToolboxController::dispose();
239 m_aListenerMap
.clear(); // Break the cycle with StyleDispatcher.
244 /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */