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>
34 using namespace com::sun::star::awt
;
35 using namespace com::sun::star::frame
;
36 using namespace com::sun::star::system
;
37 using namespace com::sun::star::uno
;
39 using com::sun::star::beans::NamedValue
;
40 using com::sun::star::beans::PropertyValue
;
41 using com::sun::star::sheet::XSpreadsheetView
;
42 using com::sun::star::text::XTextViewCursorSupplier
;
43 using com::sun::star::util::URL
;
45 ListenerHelper aListenerHelper
;
47 void BaseDispatch::ShowMessageBox( const Reference
< XFrame
>& rFrame
, const ::rtl::OUString
& aTitle
, const ::rtl::OUString
& aMsgText
)
49 if ( !mxToolkit
.is() )
50 mxToolkit
= Toolkit::create(mxContext
);
51 Reference
< XMessageBoxFactory
> xMsgBoxFactory( mxToolkit
, UNO_QUERY
);
52 if ( rFrame
.is() && xMsgBoxFactory
.is() )
54 Reference
< XMessageBox
> xMsgBox
= xMsgBoxFactory
->createMessageBox(
55 Reference
< XWindowPeer
>( rFrame
->getContainerWindow(), UNO_QUERY
),
56 Rectangle(0,0,300,200),
57 rtl::OUString( "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
) throw ( Exception
, RuntimeException
)
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
)
117 throw( RuntimeException
)
119 Reference
< XDispatch
> xRet
;
123 Reference
< XController
> xCtrl
= mxFrame
->getController();
124 if ( xCtrl
.is() && aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
126 Reference
< XTextViewCursorSupplier
> xCursor( xCtrl
, UNO_QUERY
);
127 Reference
< XSpreadsheetView
> xView( xCtrl
, UNO_QUERY
);
128 if ( !xCursor
.is() && !xView
.is() )
129 // without an appropriate corresponding document the handler doesn't function
132 if ( aURL
.Path
== "ImageButtonCmd" ||
133 aURL
.Path
== "ComboboxCmd" ||
134 aURL
.Path
== "ToggleDropdownButtonCmd" ||
135 aURL
.Path
== "DropdownButtonCmd" ||
136 aURL
.Path
== "SpinfieldCmd" ||
137 aURL
.Path
== "EditfieldCmd" ||
138 aURL
.Path
== "DropdownboxCmd" )
140 xRet
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
143 xRet
= xCursor
.is() ? (BaseDispatch
*) new WriterDispatch( mxContext
, mxFrame
) :
144 (BaseDispatch
*) new CalcDispatch( mxContext
, mxFrame
);
145 aListenerHelper
.AddDispatch( xRet
, mxFrame
, aURL
.Path
);
153 Sequence
< Reference
< XDispatch
> > SAL_CALL
MyProtocolHandler::queryDispatches( const Sequence
< DispatchDescriptor
>& seqDescripts
)
154 throw( RuntimeException
)
156 sal_Int32 nCount
= seqDescripts
.getLength();
157 Sequence
< Reference
< XDispatch
> > lDispatcher( nCount
);
159 for( sal_Int32 i
=0; i
<nCount
; ++i
)
160 lDispatcher
[i
] = queryDispatch( seqDescripts
[i
].FeatureURL
, seqDescripts
[i
].FrameName
, seqDescripts
[i
].SearchFlags
);
165 ::rtl::OUString
MyProtocolHandler_getImplementationName ()
166 throw (RuntimeException
)
168 return ::rtl::OUString( MYPROTOCOLHANDLER_IMPLEMENTATIONNAME
);
171 sal_Bool SAL_CALL
MyProtocolHandler_supportsService( const ::rtl::OUString
& ServiceName
)
172 throw (RuntimeException
)
174 return ServiceName
== MYPROTOCOLHANDLER_SERVICENAME
||
175 ServiceName
== "com.sun.star.frame.ProtocolHandler";
178 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler_getSupportedServiceNames( )
179 throw (RuntimeException
)
181 Sequence
< ::rtl::OUString
> aRet(1);
182 aRet
[0] = ::rtl::OUString( MYPROTOCOLHANDLER_SERVICENAME
);
188 Reference
< XInterface
> SAL_CALL
MyProtocolHandler_createInstance( const Reference
< XComponentContext
> & rSMgr
)
191 return (cppu::OWeakObject
*) new MyProtocolHandler( rSMgr
);
195 ::rtl::OUString SAL_CALL
MyProtocolHandler::getImplementationName( )
196 throw (RuntimeException
)
198 return MyProtocolHandler_getImplementationName();
201 sal_Bool SAL_CALL
MyProtocolHandler::supportsService( const ::rtl::OUString
& rServiceName
)
202 throw (RuntimeException
)
204 return MyProtocolHandler_supportsService( rServiceName
);
207 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler::getSupportedServiceNames( )
208 throw (RuntimeException
)
210 return MyProtocolHandler_getSupportedServiceNames();
213 void SAL_CALL
BaseDispatch::dispatch( const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
) throw (RuntimeException
)
215 /* Its neccessary to hold this object alive, till this method finish.
216 May the outside dispatch cache (implemented by the menu/toolbar!)
217 forget this instance during de-/activation of frames (focus!).
219 E.g. An open db beamer in combination with the My-Dialog
220 can force such strange situation :-(
222 Reference
< XInterface
> xSelfHold(static_cast< XDispatch
* >(this), UNO_QUERY
);
224 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
226 if ( aURL
.Path
== "ImageButtonCmd" )
228 // open the LibreOffice web page
229 ::rtl::OUString
sURL("http://www.libreoffice.org");
230 Reference
< XSystemShellExecute
> xSystemShellExecute(
231 SystemShellExecute::create(mxContext
) );
234 xSystemShellExecute
->execute( sURL
, ::rtl::OUString(), SystemShellExecuteFlags::URIS_ONLY
);
236 catch( Exception
& rEx
)
241 else if ( aURL
.Path
== "ComboboxCmd" )
243 // remove the text if it's in our list
244 Sequence
< NamedValue
> aRemoveArgs( 1 );
245 aRemoveArgs
[0].Name
= rtl::OUString( "Text" );
246 aRemoveArgs
[0].Value
<<= maComboBoxText
;
247 SendCommand( aURL
, ::rtl::OUString( "RemoveEntryText" ), aRemoveArgs
, sal_True
);
249 // add the new text to the start of the list
250 Sequence
< NamedValue
> aInsertArgs( 2 );
251 aInsertArgs
[0].Name
= rtl::OUString( "Pos" );
252 aInsertArgs
[0].Value
<<= sal_Int32( 0 );
253 aInsertArgs
[1].Name
= rtl::OUString( "Text" );
254 aInsertArgs
[1].Value
<<= maComboBoxText
;
255 SendCommand( aURL
, ::rtl::OUString("InsertEntry"), aInsertArgs
, sal_True
);
257 else if ( aURL
.Path
== "InsertEntry" )
259 // Retrieve the text argument from the sequence property value
261 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
263 if ( lArgs
[i
].Name
== "Text" )
265 lArgs
[i
].Value
>>= aText
;
270 // create new URL to address the combox box
272 aCmdURL
.Path
= "ComboboxCmd";
273 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
274 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
276 // set the selected item as text into the combobox
277 Sequence
< NamedValue
> aArgs( 1 );
278 aArgs
[0].Name
= "Text";
279 aArgs
[0].Value
<<= aText
;
280 SendCommand( aCmdURL
, ::rtl::OUString( "SetText" ), aArgs
, sal_True
);
282 else if ( aURL
.Path
== "DropdownButtonCmd" )
284 // Retrieve the text argument from the sequence property value
286 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
288 if ( lArgs
[i
].Name
== "Text" )
290 lArgs
[i
].Value
>>= aText
;
295 // just enable this command
297 // set enable flag according to selection
298 if ( aText
== "Button Disabled" )
299 mbButtonEnabled
= sal_False
;
301 mbButtonEnabled
= sal_True
;
303 // create new URL to address the image button
305 aCmdURL
.Path
= "Command1";
306 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
307 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
309 // create and initialize FeatureStateEvent with IsEnabled
310 ::com::sun::star::frame::FeatureStateEvent aEvent
;
311 aEvent
.FeatureURL
= aCmdURL
;
312 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
313 aEvent
.IsEnabled
= mbButtonEnabled
;
314 aEvent
.Requery
= sal_False
;
315 aEvent
.State
<<= Any();
317 // Notify listener about new state
318 Reference
< XDispatch
> xDispatch
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
319 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
321 else if ( aURL
.Path
== "SpinfieldCmd" )
324 else if ( aURL
.Path
== "DropdownboxCmd" )
326 // Retrieve the text argument from the sequence property value
328 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
330 if ( lArgs
[i
].Name
== "Text" )
332 lArgs
[i
].Value
>>= aText
;
336 OSL_TRACE( "Dropdownbox control - selected entry text : %s",
337 rtl::OUStringToOString( aText
, RTL_TEXTENCODING_UTF8
).getStr() );
342 void SAL_CALL
BaseDispatch::addStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
344 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
346 if ( aURL
.Path
== "ImageButtonCmd" )
348 // just enable this command
349 ::com::sun::star::frame::FeatureStateEvent aEvent
;
350 aEvent
.FeatureURL
= aURL
;
351 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
352 aEvent
.IsEnabled
= mbButtonEnabled
;
353 aEvent
.Requery
= sal_False
;
354 aEvent
.State
<<= Any();
355 xControl
->statusChanged( aEvent
);
357 else if ( aURL
.Path
== "ComboboxCmd" )
359 // just enable this command
360 ::com::sun::star::frame::FeatureStateEvent aEvent
;
361 aEvent
.FeatureURL
= aURL
;
362 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
363 aEvent
.IsEnabled
= sal_True
;
364 aEvent
.Requery
= sal_False
;
365 aEvent
.State
<<= Any();
366 xControl
->statusChanged( aEvent
);
368 else if ( aURL
.Path
== "ToggleDropdownButtonCmd" )
370 // A toggle dropdown box is normally used for a group of commands
371 // where the user can select the last issued command easily.
372 // E.g. a typical command group would be "Insert shape"
373 Sequence
< NamedValue
> aArgs( 1 );
375 // send command to set context menu content
376 Sequence
< rtl::OUString
> aContextMenu( 3 );
377 aContextMenu
[0] = "Command 1";
378 aContextMenu
[1] = "Command 2";
379 aContextMenu
[2] = "Command 3";
381 aArgs
[0].Name
= "List";
382 aArgs
[0].Value
<<= aContextMenu
;
383 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
385 // send command to check item on pos=0
386 aArgs
[0].Name
= rtl::OUString( "Pos" );
387 aArgs
[0].Value
<<= sal_Int32( 0 );
388 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
390 else if ( aURL
.Path
== "DropdownButtonCmd" )
392 // A dropdown box is normally used for a group of dependent modes, where
393 // the user can only select one. The modes cannot be combined.
394 // E.g. a typical group would be left,right,center,block.
395 Sequence
< NamedValue
> aArgs( 1 );
397 // send command to set context menu content
398 Sequence
< rtl::OUString
> aContextMenu( 2 );
399 aContextMenu
[0] = "Button Enabled";
400 aContextMenu
[1] = "Button Disabled";
402 aArgs
[0].Name
= "List";
403 aArgs
[0].Value
<<= aContextMenu
;
404 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
406 // set position according to enable/disable state of button
407 sal_Int32
nPos( mbButtonEnabled
? 0 : 1 );
409 // send command to check item on pos=0
410 aArgs
[0].Name
= "Pos";
411 aArgs
[0].Value
<<= nPos
;
412 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
414 else if ( aURL
.Path
== "SpinfieldCmd" )
417 Sequence
< NamedValue
> aArgs( 5 );
419 // send command to initialize spin button
420 aArgs
[0].Name
= "Value";
421 aArgs
[0].Value
<<= double( 0.0 );
422 aArgs
[1].Name
= "UpperLimit";
423 aArgs
[1].Value
<<= double( 10.0 );
424 aArgs
[2].Name
= "LowerLimit";
425 aArgs
[2].Value
<<= double( 0.0 );
426 aArgs
[3].Name
= "Step";
427 aArgs
[3].Value
<<= double( 0.1 );
428 aArgs
[4].Name
= "OutputFormat";
429 aArgs
[4].Value
<<= rtl::OUString("%.2f cm");
431 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetValues" ), aArgs
, sal_True
);
433 else if ( aURL
.Path
== "DropdownboxCmd" )
435 // A dropdown box is normally used for a group of commands
436 // where the user can select one of a defined set.
437 Sequence
< NamedValue
> aArgs( 1 );
439 // send command to set context menu content
440 Sequence
< rtl::OUString
> aList( 10 );
452 aArgs
[0].Name
= "List";
453 aArgs
[0].Value
<<= aList
;
454 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
457 aListenerHelper
.AddListener( mxFrame
, xControl
, aURL
.Path
);
461 void SAL_CALL
BaseDispatch::removeStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
463 aListenerHelper
.RemoveListener( mxFrame
, xControl
, aURL
.Path
);
466 void SAL_CALL
BaseDispatch::controlEvent( const ControlEvent
& Event
) throw (RuntimeException
)
468 if ( Event
.aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
470 if ( Event
.aURL
.Path
== "ComboboxCmd" )
472 // We get notifications whenever the text inside the combobox has been changed.
473 // We store the new text into a member.
474 if ( Event
.Event
== "TextChanged" )
476 rtl::OUString aNewText
;
477 sal_Bool
bHasText( sal_False
);
478 for ( sal_Int32 i
= 0; i
< Event
.aInformation
.getLength(); i
++ )
480 if ( Event
.aInformation
[i
].Name
== "Text" )
482 bHasText
= Event
.aInformation
[i
].Value
>>= aNewText
;
488 maComboBoxText
= aNewText
;
494 BaseDispatch::BaseDispatch( const Reference
< XComponentContext
> &rxContext
,
495 const Reference
< XFrame
>& xFrame
,
496 const ::rtl::OUString
& rServiceName
)
497 : mxContext( rxContext
)
499 , msDocService( rServiceName
)
500 , mbButtonEnabled( sal_True
)
505 BaseDispatch::~BaseDispatch()
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */