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
) 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 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler_getSupportedServiceNames( )
172 throw (RuntimeException
)
174 Sequence
< ::rtl::OUString
> aRet(1);
175 aRet
[0] = ::rtl::OUString( MYPROTOCOLHANDLER_SERVICENAME
);
181 Reference
< XInterface
> SAL_CALL
MyProtocolHandler_createInstance( const Reference
< XComponentContext
> & rSMgr
)
184 return (cppu::OWeakObject
*) new MyProtocolHandler( rSMgr
);
188 ::rtl::OUString SAL_CALL
MyProtocolHandler::getImplementationName( )
189 throw (RuntimeException
)
191 return MyProtocolHandler_getImplementationName();
194 sal_Bool SAL_CALL
MyProtocolHandler::supportsService( const ::rtl::OUString
& rServiceName
)
195 throw (RuntimeException
)
197 return cppu::supportsService(this, rServiceName
);
200 Sequence
< ::rtl::OUString
> SAL_CALL
MyProtocolHandler::getSupportedServiceNames( )
201 throw (RuntimeException
)
203 return MyProtocolHandler_getSupportedServiceNames();
206 void SAL_CALL
BaseDispatch::dispatch( const URL
& aURL
, const Sequence
< PropertyValue
>& lArgs
) throw (RuntimeException
)
208 /* It's necessary to hold this object alive, till this method finishes.
209 May the outside dispatch cache (implemented by the menu/toolbar!)
210 forget this instance during de-/activation of frames (focus!).
212 E.g. An open db beamer in combination with the My-Dialog
213 can force such strange situation :-(
215 Reference
< XInterface
> xSelfHold(static_cast< XDispatch
* >(this), UNO_QUERY
);
217 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
219 if ( aURL
.Path
== "ImageButtonCmd" )
221 // open the LibreOffice web page
222 ::rtl::OUString
sURL("http://www.libreoffice.org");
223 Reference
< XSystemShellExecute
> xSystemShellExecute(
224 SystemShellExecute::create(mxContext
) );
227 xSystemShellExecute
->execute( sURL
, ::rtl::OUString(), SystemShellExecuteFlags::URIS_ONLY
);
229 catch( Exception
& rEx
)
234 else if ( aURL
.Path
== "ComboboxCmd" )
236 // remove the text if it's in our list
237 Sequence
< NamedValue
> aRemoveArgs( 1 );
238 aRemoveArgs
[0].Name
= rtl::OUString( "Text" );
239 aRemoveArgs
[0].Value
<<= maComboBoxText
;
240 SendCommand( aURL
, ::rtl::OUString( "RemoveEntryText" ), aRemoveArgs
, sal_True
);
242 // add the new text to the start of the list
243 Sequence
< NamedValue
> aInsertArgs( 2 );
244 aInsertArgs
[0].Name
= rtl::OUString( "Pos" );
245 aInsertArgs
[0].Value
<<= sal_Int32( 0 );
246 aInsertArgs
[1].Name
= rtl::OUString( "Text" );
247 aInsertArgs
[1].Value
<<= maComboBoxText
;
248 SendCommand( aURL
, ::rtl::OUString("InsertEntry"), aInsertArgs
, sal_True
);
250 else if ( aURL
.Path
== "InsertEntry" )
252 // Retrieve the text argument from the sequence property value
254 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
256 if ( lArgs
[i
].Name
== "Text" )
258 lArgs
[i
].Value
>>= aText
;
263 // create new URL to address the combox box
265 aCmdURL
.Path
= "ComboboxCmd";
266 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
267 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
269 // set the selected item as text into the combobox
270 Sequence
< NamedValue
> aArgs( 1 );
271 aArgs
[0].Name
= "Text";
272 aArgs
[0].Value
<<= aText
;
273 SendCommand( aCmdURL
, ::rtl::OUString( "SetText" ), aArgs
, sal_True
);
275 else if ( aURL
.Path
== "DropdownButtonCmd" )
277 // Retrieve the text argument from the sequence property value
279 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
281 if ( lArgs
[i
].Name
== "Text" )
283 lArgs
[i
].Value
>>= aText
;
288 // just enable this command
290 // set enable flag according to selection
291 if ( aText
== "Button Disabled" )
292 mbButtonEnabled
= sal_False
;
294 mbButtonEnabled
= sal_True
;
296 // create new URL to address the image button
298 aCmdURL
.Path
= "Command1";
299 aCmdURL
.Protocol
= "vnd.demo.complextoolbarcontrols.demoaddon:";
300 aCmdURL
.Complete
= aCmdURL
.Path
+ aCmdURL
.Protocol
;
302 // create and initialize FeatureStateEvent with IsEnabled
303 ::com::sun::star::frame::FeatureStateEvent aEvent
;
304 aEvent
.FeatureURL
= aCmdURL
;
305 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
306 aEvent
.IsEnabled
= mbButtonEnabled
;
307 aEvent
.Requery
= sal_False
;
308 aEvent
.State
= Any();
310 // Notify listener about new state
311 Reference
< XDispatch
> xDispatch
= aListenerHelper
.GetDispatch( mxFrame
, aURL
.Path
);
312 aListenerHelper
.Notify( mxFrame
, aEvent
.FeatureURL
.Path
, aEvent
);
314 else if ( aURL
.Path
== "SpinfieldCmd" )
317 else if ( aURL
.Path
== "DropdownboxCmd" )
319 // Retrieve the text argument from the sequence property value
321 for ( sal_Int32 i
= 0; i
< lArgs
.getLength(); i
++ )
323 if ( lArgs
[i
].Name
== "Text" )
325 lArgs
[i
].Value
>>= aText
;
333 void SAL_CALL
BaseDispatch::addStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
335 if ( aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
337 if ( aURL
.Path
== "ImageButtonCmd" )
339 // just enable this command
340 ::com::sun::star::frame::FeatureStateEvent aEvent
;
341 aEvent
.FeatureURL
= aURL
;
342 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
343 aEvent
.IsEnabled
= mbButtonEnabled
;
344 aEvent
.Requery
= sal_False
;
345 aEvent
.State
= Any();
346 xControl
->statusChanged( aEvent
);
348 else if ( aURL
.Path
== "ComboboxCmd" )
350 // just enable this command
351 ::com::sun::star::frame::FeatureStateEvent aEvent
;
352 aEvent
.FeatureURL
= aURL
;
353 aEvent
.Source
= (::com::sun::star::frame::XDispatch
*) this;
354 aEvent
.IsEnabled
= sal_True
;
355 aEvent
.Requery
= sal_False
;
356 aEvent
.State
= Any();
357 xControl
->statusChanged( aEvent
);
359 else if ( aURL
.Path
== "ToggleDropdownButtonCmd" )
361 // A toggle dropdown box is normally used for a group of commands
362 // where the user can select the last issued command easily.
363 // E.g. a typical command group would be "Insert shape"
364 Sequence
< NamedValue
> aArgs( 1 );
366 // send command to set context menu content
367 Sequence
< rtl::OUString
> aContextMenu( 3 );
368 aContextMenu
[0] = "Command 1";
369 aContextMenu
[1] = "Command 2";
370 aContextMenu
[2] = "Command 3";
372 aArgs
[0].Name
= "List";
373 aArgs
[0].Value
<<= aContextMenu
;
374 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
376 // send command to check item on pos=0
377 aArgs
[0].Name
= rtl::OUString( "Pos" );
378 aArgs
[0].Value
<<= sal_Int32( 0 );
379 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
381 else if ( aURL
.Path
== "DropdownButtonCmd" )
383 // A dropdown box is normally used for a group of dependent modes, where
384 // the user can only select one. The modes cannot be combined.
385 // E.g. a typical group would be left,right,center,block.
386 Sequence
< NamedValue
> aArgs( 1 );
388 // send command to set context menu content
389 Sequence
< rtl::OUString
> aContextMenu( 2 );
390 aContextMenu
[0] = "Button Enabled";
391 aContextMenu
[1] = "Button Disabled";
393 aArgs
[0].Name
= "List";
394 aArgs
[0].Value
<<= aContextMenu
;
395 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
397 // set position according to enable/disable state of button
398 sal_Int32
nPos( mbButtonEnabled
? 0 : 1 );
400 // send command to check item on pos=0
401 aArgs
[0].Name
= "Pos";
402 aArgs
[0].Value
<<= nPos
;
403 SendCommandTo( xControl
, aURL
, ::rtl::OUString( "CheckItemPos" ), aArgs
, sal_True
);
405 else if ( aURL
.Path
== "SpinfieldCmd" )
408 Sequence
< NamedValue
> aArgs( 5 );
410 // send command to initialize spin button
411 aArgs
[0].Name
= "Value";
412 aArgs
[0].Value
<<= double( 0.0 );
413 aArgs
[1].Name
= "UpperLimit";
414 aArgs
[1].Value
<<= double( 10.0 );
415 aArgs
[2].Name
= "LowerLimit";
416 aArgs
[2].Value
<<= double( 0.0 );
417 aArgs
[3].Name
= "Step";
418 aArgs
[3].Value
<<= double( 0.1 );
419 aArgs
[4].Name
= "OutputFormat";
420 aArgs
[4].Value
<<= rtl::OUString("%.2f cm");
422 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetValues" ), aArgs
, sal_True
);
424 else if ( aURL
.Path
== "DropdownboxCmd" )
426 // A dropdown box is normally used for a group of commands
427 // where the user can select one of a defined set.
428 Sequence
< NamedValue
> aArgs( 1 );
430 // send command to set context menu content
431 Sequence
< rtl::OUString
> aList( 10 );
443 aArgs
[0].Name
= "List";
444 aArgs
[0].Value
<<= aList
;
445 SendCommandTo( xControl
, aURL
, rtl::OUString( "SetList" ), aArgs
, sal_True
);
448 aListenerHelper
.AddListener( mxFrame
, xControl
, aURL
.Path
);
452 void SAL_CALL
BaseDispatch::removeStatusListener( const Reference
< XStatusListener
>& xControl
, const URL
& aURL
) throw (RuntimeException
)
454 aListenerHelper
.RemoveListener( mxFrame
, xControl
, aURL
.Path
);
457 void SAL_CALL
BaseDispatch::controlEvent( const ControlEvent
& Event
) throw (RuntimeException
)
459 if ( Event
.aURL
.Protocol
== "vnd.demo.complextoolbarcontrols.demoaddon:" )
461 if ( Event
.aURL
.Path
== "ComboboxCmd" )
463 // We get notifications whenever the text inside the combobox has been changed.
464 // We store the new text into a member.
465 if ( Event
.Event
== "TextChanged" )
467 rtl::OUString aNewText
;
468 sal_Bool
bHasText( sal_False
);
469 for ( sal_Int32 i
= 0; i
< Event
.aInformation
.getLength(); i
++ )
471 if ( Event
.aInformation
[i
].Name
== "Text" )
473 bHasText
= Event
.aInformation
[i
].Value
>>= aNewText
;
479 maComboBoxText
= aNewText
;
485 BaseDispatch::BaseDispatch( const Reference
< XComponentContext
> &rxContext
,
486 const Reference
< XFrame
>& xFrame
,
487 const ::rtl::OUString
& rServiceName
)
488 : mxContext( rxContext
)
490 , msDocService( rServiceName
)
491 , mbButtonEnabled( sal_True
)
495 BaseDispatch::~BaseDispatch()
501 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */