1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include "ListenerHelper.h"
22 #include "MyProtocolHandler.h"
24 #include <com/sun/star/awt/MessageBoxButtons.hpp>
25 #include <com/sun/star/awt/Toolkit.hpp>
26 #include <com/sun/star/awt/XMessageBoxFactory.hpp>
27 #include <com/sun/star/frame/ControlCommand.hpp>
28 #include <com/sun/star/text/XTextViewCursorSupplier.hpp>
29 #include <com/sun/star/sheet/XSpreadsheetView.hpp>
30 #include <com/sun/star/system/SystemShellExecute.hpp>
31 #include <com/sun/star/system/SystemShellExecuteFlags.hpp>
32 #include <com/sun/star/system/XSystemShellExecute.hpp>
33 #include <cppuhelper/supportsservice.hxx>
35 using namespace com::sun::star::awt
;
36 using namespace com::sun::star::frame
;
37 using namespace com::sun::star::system
;
38 using namespace com::sun::star::uno
;
40 using com::sun::star::beans::NamedValue
;
41 using com::sun::star::beans::PropertyValue
;
42 using com::sun::star::sheet::XSpreadsheetView
;
43 using com::sun::star::text::XTextViewCursorSupplier
;
44 using com::sun::star::util::URL
;
46 ListenerHelper aListenerHelper
;
48 void BaseDispatch::ShowMessageBox( const Reference
< XFrame
>& rFrame
, const ::rtl::OUString
& aTitle
, const ::rtl::OUString
& aMsgText
)
50 if ( !mxToolkit
.is() )
51 mxToolkit
= Toolkit::create(mxContext
);
52 Reference
< XMessageBoxFactory
> xMsgBoxFactory( mxToolkit
, UNO_QUERY
);
53 if ( rFrame
.is() && xMsgBoxFactory
.is() )
55 Reference
< XMessageBox
> xMsgBox
= xMsgBoxFactory
->createMessageBox(
56 Reference
< XWindowPeer
>( rFrame
->getContainerWindow(), UNO_QUERY
),
57 com::sun::star::awt::MessageBoxType_INFOBOX
,
58 MessageBoxButtons::BUTTONS_OK
,
67 void BaseDispatch::SendCommand( const com::sun::star::util::URL
& aURL
, const ::rtl::OUString
& rCommand
, const Sequence
< NamedValue
>& rArgs
, sal_Bool bEnabled
)
69 Reference
< XDispatch
> xDispatch
=
70 aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
72 FeatureStateEvent aEvent
;
74 aEvent
.FeatureURL
= aURL
;
75 aEvent
.Source
= xDispatch
;
76 aEvent
.IsEnabled
= bEnabled
;
77 aEvent
.Requery
= sal_False
;
79 ControlCommand aCtrlCmd
;
80 aCtrlCmd
.Command
= rCommand
;
81 aCtrlCmd
.Arguments
= rArgs
;
83 aEvent
.State
<<= aCtrlCmd
;
84 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
87 void BaseDispatch::SendCommandTo( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
, const ::rtl::OUString
& rCommand
, const Sequence
< NamedValue
>& rArgs
, sal_Bool bEnabled
)
89 FeatureStateEvent aEvent
;
91 aEvent
.FeatureURL
= aURL
;
92 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
93 aEvent
.IsEnabled
= bEnabled
;
94 aEvent
.Requery
= sal_False
;
96 ControlCommand aCtrlCmd
;
97 aCtrlCmd
.Command
= rCommand
;
98 aCtrlCmd
.Arguments
= rArgs
;
100 aEvent
.State
<<= aCtrlCmd
;
101 xControl
->statusChanged( aEvent
);
104 void SAL_CALL
MyProtocolHandler::initialize( const Sequence
< Any
>& aArguments
)
106 Reference
< XFrame
> xFrame
;
107 if ( aArguments
.getLength() )
109 // the first Argument is always the Frame, as a ProtocolHandler needs to have access
110 // to the context in which it is invoked.
111 aArguments
[0] >>= xFrame
;
116 Reference
< XDispatch
> SAL_CALL
MyProtocolHandler::queryDispatch( const URL
& aURL
, const ::rtl::OUString
& sTargetFrameName
, sal_Int32 nSearchFlags
)
118 Reference
< XDispatch
> xRet
;
122 Reference
< XController
> xCtrl
= mxFrame
->getController();
123 if ( xCtrl
.is() && aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
125 Reference
< XTextViewCursorSupplier
> xCursor( xCtrl
, UNO_QUERY
);
126 Reference
< XSpreadsheetView
> xView( xCtrl
, UNO_QUERY
);
127 if ( !xCursor
.is() && !xView
.is() )
128 // without an appropriate corresponding document the handler doesn't function
131 if ( aURL
.Path
== "ImageButtonCmd" ||
132 aURL
.Path
== "ComboboxCmd" ||
133 aURL
.Path
== "ToggleDropdownButtonCmd" ||
134 aURL
.Path
== "DropdownButtonCmd" ||
135 aURL
.Path
== "SpinfieldCmd" ||
136 aURL
.Path
== "EditfieldCmd" ||
137 aURL
.Path
== "DropdownboxCmd" )
139 xRet
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
142 xRet
= xCursor
.is() ? (BaseDispatch
*) new WriterDispatch( mxContext
, mxFrame
) :
143 (BaseDispatch
*) new CalcDispatch( mxContext
, mxFrame
);
144 aListenerHelper
.AddDispatch( xRet
, mxFrame
, aURL
.Path
);
152 Sequence
< Reference
< XDispatch
> > SAL_CALL
MyProtocolHandler::queryDispatches( const Sequence
< DispatchDescriptor
>& seqDescripts
)
154 sal_Int32 nCount
= seqDescripts
.getLength();
155 Sequence
< Reference
< XDispatch
> > lDispatcher( nCount
);
157 for( sal_Int32 i
=0; i
<nCount
; ++i
)
158 lDispatcher
[i
] = queryDispatch( seqDescripts
[i
].FeatureURL
, seqDescripts
[i
].FrameName
, seqDescripts
[i
].SearchFlags
);
163 ::rtl::OUString
MyProtocolHandler_getImplementationName ()
165 return ::rtl::OUString( MYPROTOCOLHANDLER_IMPLEMENTATIONNAME
);
168 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler_getSupportedServiceNames( )
170 Sequence
< ::rtl::OUString
> aRet(1);
171 aRet
[0] = ::rtl::OUString( MYPROTOCOLHANDLER_SERVICENAME
);
177 Reference
< XInterface
> SAL_CALL
MyProtocolHandler_createInstance( const Reference
< XComponentContext
> & rSMgr
)
179 return (cppu::OWeakObject
*) new MyProtocolHandler( rSMgr
);
183 ::rtl::OUString SAL_CALL
MyProtocolHandler::getImplementationName( )
185 return MyProtocolHandler_getImplementationName();
188 sal_Bool SAL_CALL
MyProtocolHandler::supportsService( const ::rtl::OUString
& rServiceName
)
190 return cppu::supportsService(this, rServiceName
);
193 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler::getSupportedServiceNames( )
195 return MyProtocolHandler_getSupportedServiceNames();
198 void SAL_CALL
BaseDispatch::dispatch( const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
)
200 /* It's necessary to hold this object alive, till this method finishes.
201 May the outside dispatch cache (implemented by the menu/toolbar!)
202 forget this instance during de-/activation of frames (focus!).
204 E.g. An open db beamer in combination with the My-Dialog
205 can force such strange situation :-(
207 Reference
< XInterface
> xSelfHold(static_cast< XDispatch
* >(this), UNO_QUERY
);
209 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
211 if ( aURL
.Path
== "ImageButtonCmd" )
213 // open the LibreOffice web page
214 ::rtl::OUString
sURL("http://www.libreoffice.org");
215 Reference
< XSystemShellExecute
> xSystemShellExecute(
216 SystemShellExecute::create(mxContext
) );
219 xSystemShellExecute
->execute( sURL
, ::rtl::OUString(), SystemShellExecuteFlags::URIS_ONLY
);
221 catch( Exception
& rEx
)
226 else if ( aURL
.Path
== "ComboboxCmd" )
228 // remove the text if it's in our list
229 Sequence
< NamedValue
> aRemoveArgs( 1 );
230 aRemoveArgs
[0].Name
= rtl::OUString( "Text" );
231 aRemoveArgs
[0].Value
<<= maComboBoxText
;
232 SendCommand( aURL
, ::rtl::OUString( "RemoveEntryText" ), aRemoveArgs
, sal_True
);
234 // add the new text to the start of the list
235 Sequence
< NamedValue
> aInsertArgs( 2 );
236 aInsertArgs
[0].Name
= rtl::OUString( "Pos" );
237 aInsertArgs
[0].Value
<<= sal_Int32( 0 );
238 aInsertArgs
[1].Name
= rtl::OUString( "Text" );
239 aInsertArgs
[1].Value
<<= maComboBoxText
;
240 SendCommand( aURL
, ::rtl::OUString("InsertEntry"), aInsertArgs
, sal_True
);
242 else if ( aURL
.Path
== "InsertEntry" )
244 // Retrieve the text argument from the sequence property value
246 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
248 if ( lArgs
[i
].Name
== "Text" )
250 lArgs
[i
].Value
>>= aText
;
255 // create new URL to address the combox box
257 aCmdURL
.Path
= "ComboboxCmd";
258 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
259 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
261 // set the selected item as text into the combobox
262 Sequence
< NamedValue
> aArgs( 1 );
263 aArgs
[0].Name
= "Text";
264 aArgs
[0].Value
<<= aText
;
265 SendCommand( aCmdURL
, ::rtl::OUString( "SetText" ), aArgs
, sal_True
);
267 else if ( aURL
.Path
== "DropdownButtonCmd" )
269 // Retrieve the text argument from the sequence property value
271 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
273 if ( lArgs
[i
].Name
== "Text" )
275 lArgs
[i
].Value
>>= aText
;
280 // just enable this command
282 // set enable flag according to selection
283 if ( aText
== "Button Disabled" )
284 mbButtonEnabled
= sal_False
;
286 mbButtonEnabled
= sal_True
;
288 // create new URL to address the image button
290 aCmdURL
.Path
= "Command1";
291 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
292 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
294 // create and initialize FeatureStateEvent with IsEnabled
295 ::com::sun::star::frame::FeatureStateEvent aEvent
;
296 aEvent
.FeatureURL
= aCmdURL
;
297 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
298 aEvent
.IsEnabled
= mbButtonEnabled
;
299 aEvent
.Requery
= sal_False
;
300 aEvent
.State
= Any();
302 // Notify listener about new state
303 Reference
< XDispatch
> xDispatch
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
304 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
306 else if ( aURL
.Path
== "SpinfieldCmd" )
309 else if ( aURL
.Path
== "DropdownboxCmd" )
311 // Retrieve the text argument from the sequence property value
313 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
315 if ( lArgs
[i
].Name
== "Text" )
317 lArgs
[i
].Value
>>= aText
;
325 void SAL_CALL
BaseDispatch::addStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
)
327 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
329 if ( aURL
.Path
== "ImageButtonCmd" )
331 // just enable this command
332 ::com::sun::star::frame::FeatureStateEvent aEvent
;
333 aEvent
.FeatureURL
= aURL
;
334 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
335 aEvent
.IsEnabled
= mbButtonEnabled
;
336 aEvent
.Requery
= sal_False
;
337 aEvent
.State
= Any();
338 xControl
->statusChanged( aEvent
);
340 else if ( aURL
.Path
== "ComboboxCmd" )
342 // just enable this command
343 ::com::sun::star::frame::FeatureStateEvent aEvent
;
344 aEvent
.FeatureURL
= aURL
;
345 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
346 aEvent
.IsEnabled
= sal_True
;
347 aEvent
.Requery
= sal_False
;
348 aEvent
.State
= Any();
349 xControl
->statusChanged( aEvent
);
351 else if ( aURL
.Path
== "ToggleDropdownButtonCmd" )
353 // A toggle dropdown box is normally used for a group of commands
354 // where the user can select the last issued command easily.
355 // E.g. a typical command group would be "Insert shape"
356 Sequence
< NamedValue
> aArgs( 1 );
358 // send command to set context menu content
359 Sequence
< rtl::OUString
> aContextMenu( 3 );
360 aContextMenu
[0] = "Command 1";
361 aContextMenu
[1] = "Command 2";
362 aContextMenu
[2] = "Command 3";
364 aArgs
[0].Name
= "List";
365 aArgs
[0].Value
<<= aContextMenu
;
366 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
368 // send command to check item on pos=0
369 aArgs
[0].Name
= rtl::OUString( "Pos" );
370 aArgs
[0].Value
<<= sal_Int32( 0 );
371 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
373 else if ( aURL
.Path
== "DropdownButtonCmd" )
375 // A dropdown box is normally used for a group of dependent modes, where
376 // the user can only select one. The modes cannot be combined.
377 // E.g. a typical group would be left,right,center,block.
378 Sequence
< NamedValue
> aArgs( 1 );
380 // send command to set context menu content
381 Sequence
< rtl::OUString
> aContextMenu( 2 );
382 aContextMenu
[0] = "Button Enabled";
383 aContextMenu
[1] = "Button Disabled";
385 aArgs
[0].Name
= "List";
386 aArgs
[0].Value
<<= aContextMenu
;
387 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
389 // set position according to enable/disable state of button
390 sal_Int32
nPos( mbButtonEnabled
? 0 : 1 );
392 // send command to check item on pos=0
393 aArgs
[0].Name
= "Pos";
394 aArgs
[0].Value
<<= nPos
;
395 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
397 else if ( aURL
.Path
== "SpinfieldCmd" )
400 Sequence
< NamedValue
> aArgs( 5 );
402 // send command to initialize spin button
403 aArgs
[0].Name
= "Value";
404 aArgs
[0].Value
<<= double( 0.0 );
405 aArgs
[1].Name
= "UpperLimit";
406 aArgs
[1].Value
<<= double( 10.0 );
407 aArgs
[2].Name
= "LowerLimit";
408 aArgs
[2].Value
<<= double( 0.0 );
409 aArgs
[3].Name
= "Step";
410 aArgs
[3].Value
<<= double( 0.1 );
411 aArgs
[4].Name
= "OutputFormat";
412 aArgs
[4].Value
<<= rtl::OUString("%.2f cm");
414 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetValues" ), aArgs
, sal_True
);
416 else if ( aURL
.Path
== "DropdownboxCmd" )
418 // A dropdown box is normally used for a group of commands
419 // where the user can select one of a defined set.
420 Sequence
< NamedValue
> aArgs( 1 );
422 // send command to set context menu content
423 Sequence
< rtl::OUString
> aList( 10 );
435 aArgs
[0].Name
= "List";
436 aArgs
[0].Value
<<= aList
;
437 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
440 aListenerHelper
.AddListener( mxFrame
, xControl
, aURL
.Path
);
444 void SAL_CALL
BaseDispatch::removeStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
)
446 aListenerHelper
.RemoveListener( mxFrame
, xControl
, aURL
.Path
);
449 void SAL_CALL
BaseDispatch::controlEvent( const ControlEvent
& Event
)
451 if ( Event
.aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
453 if ( Event
.aURL
.Path
== "ComboboxCmd" )
455 // We get notifications whenever the text inside the combobox has been changed.
456 // We store the new text into a member.
457 if ( Event
.Event
== "TextChanged" )
459 rtl::OUString aNewText
;
460 sal_Bool
bHasText( sal_False
);
461 for ( sal_Int32 i
= 0; i
< Event
.aInformation
.getLength(); i
++ )
463 if ( Event
.aInformation
[i
].Name
== "Text" )
465 bHasText
= Event
.aInformation
[i
].Value
>>= aNewText
;
471 maComboBoxText
= aNewText
;
477 BaseDispatch::BaseDispatch( const Reference
< XComponentContext
> &rxContext
,
478 const Reference
< XFrame
>& xFrame
,
479 const ::rtl::OUString
& rServiceName
)
480 : mxContext( rxContext
)
482 , msDocService( rServiceName
)
483 , mbButtonEnabled( sal_True
)
487 BaseDispatch::~BaseDispatch()
493 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */