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>
34 #include <osl/diagnose.h>
36 using namespace com::sun::star::awt
;
37 using namespace com::sun::star::frame
;
38 using namespace com::sun::star::system
;
39 using namespace com::sun::star::uno
;
41 using com::sun::star::beans::NamedValue
;
42 using com::sun::star::beans::PropertyValue
;
43 using com::sun::star::sheet::XSpreadsheetView
;
44 using com::sun::star::text::XTextViewCursorSupplier
;
45 using com::sun::star::util::URL
;
47 ListenerHelper aListenerHelper
;
49 void BaseDispatch::ShowMessageBox( const Reference
< XFrame
>& rFrame
, const ::rtl::OUString
& aTitle
, const ::rtl::OUString
& aMsgText
)
51 if ( !mxToolkit
.is() )
52 mxToolkit
= Toolkit::create(mxContext
);
53 Reference
< XMessageBoxFactory
> xMsgBoxFactory( mxToolkit
, UNO_QUERY
);
54 if ( rFrame
.is() && xMsgBoxFactory
.is() )
56 Reference
< XMessageBox
> xMsgBox
= xMsgBoxFactory
->createMessageBox(
57 Reference
< XWindowPeer
>( rFrame
->getContainerWindow(), UNO_QUERY
),
58 com::sun::star::awt::MessageBoxType_INFOBOX
,
59 MessageBoxButtons::BUTTONS_OK
,
68 void BaseDispatch::SendCommand( const com::sun::star::util::URL
& aURL
, const ::rtl::OUString
& rCommand
, const Sequence
< NamedValue
>& rArgs
, sal_Bool bEnabled
)
70 Reference
< XDispatch
> xDispatch
=
71 aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
73 FeatureStateEvent aEvent
;
75 aEvent
.FeatureURL
= aURL
;
76 aEvent
.Source
= xDispatch
;
77 aEvent
.IsEnabled
= bEnabled
;
78 aEvent
.Requery
= sal_False
;
80 ControlCommand aCtrlCmd
;
81 aCtrlCmd
.Command
= rCommand
;
82 aCtrlCmd
.Arguments
= rArgs
;
84 aEvent
.State
<<= aCtrlCmd
;
85 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
88 void BaseDispatch::SendCommandTo( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
, const ::rtl::OUString
& rCommand
, const Sequence
< NamedValue
>& rArgs
, sal_Bool bEnabled
)
90 FeatureStateEvent aEvent
;
92 aEvent
.FeatureURL
= aURL
;
93 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
94 aEvent
.IsEnabled
= bEnabled
;
95 aEvent
.Requery
= sal_False
;
97 ControlCommand aCtrlCmd
;
98 aCtrlCmd
.Command
= rCommand
;
99 aCtrlCmd
.Arguments
= rArgs
;
101 aEvent
.State
<<= aCtrlCmd
;
102 xControl
->statusChanged( aEvent
);
105 void SAL_CALL
MyProtocolHandler::initialize( const Sequence
< Any
>& aArguments
) throw ( Exception
, RuntimeException
)
107 Reference
< XFrame
> xFrame
;
108 if ( aArguments
.getLength() )
110 // the first Argument is always the Frame, as a ProtocolHandler needs to have access
111 // to the context in which it is invoked.
112 aArguments
[0] >>= xFrame
;
117 Reference
< XDispatch
> SAL_CALL
MyProtocolHandler::queryDispatch( const URL
& aURL
, const ::rtl::OUString
& sTargetFrameName
, sal_Int32 nSearchFlags
)
118 throw( RuntimeException
)
120 Reference
< XDispatch
> xRet
;
124 Reference
< XController
> xCtrl
= mxFrame
->getController();
125 if ( xCtrl
.is() && aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
127 Reference
< XTextViewCursorSupplier
> xCursor( xCtrl
, UNO_QUERY
);
128 Reference
< XSpreadsheetView
> xView( xCtrl
, UNO_QUERY
);
129 if ( !xCursor
.is() && !xView
.is() )
130 // without an appropriate corresponding document the handler doesn't function
133 if ( aURL
.Path
== "ImageButtonCmd" ||
134 aURL
.Path
== "ComboboxCmd" ||
135 aURL
.Path
== "ToggleDropdownButtonCmd" ||
136 aURL
.Path
== "DropdownButtonCmd" ||
137 aURL
.Path
== "SpinfieldCmd" ||
138 aURL
.Path
== "EditfieldCmd" ||
139 aURL
.Path
== "DropdownboxCmd" )
141 xRet
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
144 xRet
= xCursor
.is() ? (BaseDispatch
*) new WriterDispatch( mxContext
, mxFrame
) :
145 (BaseDispatch
*) new CalcDispatch( mxContext
, mxFrame
);
146 aListenerHelper
.AddDispatch( xRet
, mxFrame
, aURL
.Path
);
154 Sequence
< Reference
< XDispatch
> > SAL_CALL
MyProtocolHandler::queryDispatches( const Sequence
< DispatchDescriptor
>& seqDescripts
)
155 throw( RuntimeException
)
157 sal_Int32 nCount
= seqDescripts
.getLength();
158 Sequence
< Reference
< XDispatch
> > lDispatcher( nCount
);
160 for( sal_Int32 i
=0; i
<nCount
; ++i
)
161 lDispatcher
[i
] = queryDispatch( seqDescripts
[i
].FeatureURL
, seqDescripts
[i
].FrameName
, seqDescripts
[i
].SearchFlags
);
166 ::rtl::OUString
MyProtocolHandler_getImplementationName ()
167 throw (RuntimeException
)
169 return ::rtl::OUString( MYPROTOCOLHANDLER_IMPLEMENTATIONNAME
);
172 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler_getSupportedServiceNames( )
173 throw (RuntimeException
)
175 Sequence
< ::rtl::OUString
> aRet(1);
176 aRet
[0] = ::rtl::OUString( MYPROTOCOLHANDLER_SERVICENAME
);
182 Reference
< XInterface
> SAL_CALL
MyProtocolHandler_createInstance( const Reference
< XComponentContext
> & rSMgr
)
185 return (cppu::OWeakObject
*) new MyProtocolHandler( rSMgr
);
189 ::rtl::OUString SAL_CALL
MyProtocolHandler::getImplementationName( )
190 throw (RuntimeException
)
192 return MyProtocolHandler_getImplementationName();
195 sal_Bool SAL_CALL
MyProtocolHandler::supportsService( const ::rtl::OUString
& rServiceName
)
196 throw (RuntimeException
)
198 return cppu::supportsService(this, rServiceName
);
201 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler::getSupportedServiceNames( )
202 throw (RuntimeException
)
204 return MyProtocolHandler_getSupportedServiceNames();
207 void SAL_CALL
BaseDispatch::dispatch( const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
) throw (RuntimeException
)
209 /* Its necessary to hold this object alive, till this method finish.
210 May the outside dispatch cache (implemented by the menu/toolbar!)
211 forget this instance during de-/activation of frames (focus!).
213 E.g. An open db beamer in combination with the My-Dialog
214 can force such strange situation :-(
216 Reference
< XInterface
> xSelfHold(static_cast< XDispatch
* >(this), UNO_QUERY
);
218 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
220 if ( aURL
.Path
== "ImageButtonCmd" )
222 // open the LibreOffice web page
223 ::rtl::OUString
sURL("http://www.libreoffice.org");
224 Reference
< XSystemShellExecute
> xSystemShellExecute(
225 SystemShellExecute::create(mxContext
) );
228 xSystemShellExecute
->execute( sURL
, ::rtl::OUString(), SystemShellExecuteFlags::URIS_ONLY
);
230 catch( Exception
& rEx
)
235 else if ( aURL
.Path
== "ComboboxCmd" )
237 // remove the text if it's in our list
238 Sequence
< NamedValue
> aRemoveArgs( 1 );
239 aRemoveArgs
[0].Name
= rtl::OUString( "Text" );
240 aRemoveArgs
[0].Value
<<= maComboBoxText
;
241 SendCommand( aURL
, ::rtl::OUString( "RemoveEntryText" ), aRemoveArgs
, sal_True
);
243 // add the new text to the start of the list
244 Sequence
< NamedValue
> aInsertArgs( 2 );
245 aInsertArgs
[0].Name
= rtl::OUString( "Pos" );
246 aInsertArgs
[0].Value
<<= sal_Int32( 0 );
247 aInsertArgs
[1].Name
= rtl::OUString( "Text" );
248 aInsertArgs
[1].Value
<<= maComboBoxText
;
249 SendCommand( aURL
, ::rtl::OUString("InsertEntry"), aInsertArgs
, sal_True
);
251 else if ( aURL
.Path
== "InsertEntry" )
253 // Retrieve the text argument from the sequence property value
255 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
257 if ( lArgs
[i
].Name
== "Text" )
259 lArgs
[i
].Value
>>= aText
;
264 // create new URL to address the combox box
266 aCmdURL
.Path
= "ComboboxCmd";
267 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
268 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
270 // set the selected item as text into the combobox
271 Sequence
< NamedValue
> aArgs( 1 );
272 aArgs
[0].Name
= "Text";
273 aArgs
[0].Value
<<= aText
;
274 SendCommand( aCmdURL
, ::rtl::OUString( "SetText" ), aArgs
, sal_True
);
276 else if ( aURL
.Path
== "DropdownButtonCmd" )
278 // Retrieve the text argument from the sequence property value
280 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
282 if ( lArgs
[i
].Name
== "Text" )
284 lArgs
[i
].Value
>>= aText
;
289 // just enable this command
291 // set enable flag according to selection
292 if ( aText
== "Button Disabled" )
293 mbButtonEnabled
= sal_False
;
295 mbButtonEnabled
= sal_True
;
297 // create new URL to address the image button
299 aCmdURL
.Path
= "Command1";
300 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
301 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
303 // create and initialize FeatureStateEvent with IsEnabled
304 ::com::sun::star::frame::FeatureStateEvent aEvent
;
305 aEvent
.FeatureURL
= aCmdURL
;
306 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
307 aEvent
.IsEnabled
= mbButtonEnabled
;
308 aEvent
.Requery
= sal_False
;
309 aEvent
.State
<<= Any();
311 // Notify listener about new state
312 Reference
< XDispatch
> xDispatch
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
313 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
315 else if ( aURL
.Path
== "SpinfieldCmd" )
318 else if ( aURL
.Path
== "DropdownboxCmd" )
320 // Retrieve the text argument from the sequence property value
322 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
324 if ( lArgs
[i
].Name
== "Text" )
326 lArgs
[i
].Value
>>= aText
;
330 OSL_TRACE( "Dropdownbox control - selected entry text : %s",
331 rtl::OUStringToOString( aText
, RTL_TEXTENCODING_UTF8
).getStr() );
336 void SAL_CALL
BaseDispatch::addStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
338 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
340 if ( aURL
.Path
== "ImageButtonCmd" )
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
= mbButtonEnabled
;
347 aEvent
.Requery
= sal_False
;
348 aEvent
.State
<<= Any();
349 xControl
->statusChanged( aEvent
);
351 else if ( aURL
.Path
== "ComboboxCmd" )
353 // just enable this command
354 ::com::sun::star::frame::FeatureStateEvent aEvent
;
355 aEvent
.FeatureURL
= aURL
;
356 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
357 aEvent
.IsEnabled
= sal_True
;
358 aEvent
.Requery
= sal_False
;
359 aEvent
.State
<<= Any();
360 xControl
->statusChanged( aEvent
);
362 else if ( aURL
.Path
== "ToggleDropdownButtonCmd" )
364 // A toggle dropdown box is normally used for a group of commands
365 // where the user can select the last issued command easily.
366 // E.g. a typical command group would be "Insert shape"
367 Sequence
< NamedValue
> aArgs( 1 );
369 // send command to set context menu content
370 Sequence
< rtl::OUString
> aContextMenu( 3 );
371 aContextMenu
[0] = "Command 1";
372 aContextMenu
[1] = "Command 2";
373 aContextMenu
[2] = "Command 3";
375 aArgs
[0].Name
= "List";
376 aArgs
[0].Value
<<= aContextMenu
;
377 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
379 // send command to check item on pos=0
380 aArgs
[0].Name
= rtl::OUString( "Pos" );
381 aArgs
[0].Value
<<= sal_Int32( 0 );
382 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
384 else if ( aURL
.Path
== "DropdownButtonCmd" )
386 // A dropdown box is normally used for a group of dependent modes, where
387 // the user can only select one. The modes cannot be combined.
388 // E.g. a typical group would be left,right,center,block.
389 Sequence
< NamedValue
> aArgs( 1 );
391 // send command to set context menu content
392 Sequence
< rtl::OUString
> aContextMenu( 2 );
393 aContextMenu
[0] = "Button Enabled";
394 aContextMenu
[1] = "Button Disabled";
396 aArgs
[0].Name
= "List";
397 aArgs
[0].Value
<<= aContextMenu
;
398 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
400 // set position according to enable/disable state of button
401 sal_Int32
nPos( mbButtonEnabled
? 0 : 1 );
403 // send command to check item on pos=0
404 aArgs
[0].Name
= "Pos";
405 aArgs
[0].Value
<<= nPos
;
406 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
408 else if ( aURL
.Path
== "SpinfieldCmd" )
411 Sequence
< NamedValue
> aArgs( 5 );
413 // send command to initialize spin button
414 aArgs
[0].Name
= "Value";
415 aArgs
[0].Value
<<= double( 0.0 );
416 aArgs
[1].Name
= "UpperLimit";
417 aArgs
[1].Value
<<= double( 10.0 );
418 aArgs
[2].Name
= "LowerLimit";
419 aArgs
[2].Value
<<= double( 0.0 );
420 aArgs
[3].Name
= "Step";
421 aArgs
[3].Value
<<= double( 0.1 );
422 aArgs
[4].Name
= "OutputFormat";
423 aArgs
[4].Value
<<= rtl::OUString("%.2f cm");
425 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetValues" ), aArgs
, sal_True
);
427 else if ( aURL
.Path
== "DropdownboxCmd" )
429 // A dropdown box is normally used for a group of commands
430 // where the user can select one of a defined set.
431 Sequence
< NamedValue
> aArgs( 1 );
433 // send command to set context menu content
434 Sequence
< rtl::OUString
> aList( 10 );
446 aArgs
[0].Name
= "List";
447 aArgs
[0].Value
<<= aList
;
448 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
451 aListenerHelper
.AddListener( mxFrame
, xControl
, aURL
.Path
);
455 void SAL_CALL
BaseDispatch::removeStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
457 aListenerHelper
.RemoveListener( mxFrame
, xControl
, aURL
.Path
);
460 void SAL_CALL
BaseDispatch::controlEvent( const ControlEvent
& Event
) throw (RuntimeException
)
462 if ( Event
.aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
464 if ( Event
.aURL
.Path
== "ComboboxCmd" )
466 // We get notifications whenever the text inside the combobox has been changed.
467 // We store the new text into a member.
468 if ( Event
.Event
== "TextChanged" )
470 rtl::OUString aNewText
;
471 sal_Bool
bHasText( sal_False
);
472 for ( sal_Int32 i
= 0; i
< Event
.aInformation
.getLength(); i
++ )
474 if ( Event
.aInformation
[i
].Name
== "Text" )
476 bHasText
= Event
.aInformation
[i
].Value
>>= aNewText
;
482 maComboBoxText
= aNewText
;
488 BaseDispatch::BaseDispatch( const Reference
< XComponentContext
> &rxContext
,
489 const Reference
< XFrame
>& xFrame
,
490 const ::rtl::OUString
& rServiceName
)
491 : mxContext( rxContext
)
493 , msDocService( rServiceName
)
494 , mbButtonEnabled( sal_True
)
498 BaseDispatch::~BaseDispatch()
504 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */