diff options
Diffstat (limited to 'framework/source/dispatch')
-rw-r--r-- | framework/source/dispatch/closedispatcher.cxx | 656 | ||||
-rw-r--r-- | framework/source/dispatch/dispatchinformationprovider.cxx | 193 | ||||
-rw-r--r-- | framework/source/dispatch/dispatchprovider.cxx | 798 | ||||
-rw-r--r-- | framework/source/dispatch/helpagentdispatcher.cxx | 446 | ||||
-rw-r--r-- | framework/source/dispatch/interaction.cxx | 212 | ||||
-rw-r--r-- | framework/source/dispatch/interceptionhelper.cxx | 343 | ||||
-rw-r--r-- | framework/source/dispatch/loaddispatcher.cxx | 201 | ||||
-rw-r--r-- | framework/source/dispatch/mailtodispatcher.cxx | 333 | ||||
-rw-r--r-- | framework/source/dispatch/makefile.mk | 63 | ||||
-rw-r--r-- | framework/source/dispatch/menudispatcher.cxx | 488 | ||||
-rw-r--r-- | framework/source/dispatch/oxt_handler.cxx | 283 | ||||
-rw-r--r-- | framework/source/dispatch/popupmenudispatcher.cxx | 422 | ||||
-rw-r--r-- | framework/source/dispatch/servicehandler.cxx | 354 | ||||
-rw-r--r-- | framework/source/dispatch/startmoduledispatcher.cxx | 244 | ||||
-rw-r--r-- | framework/source/dispatch/systemexec.cxx | 237 | ||||
-rw-r--r-- | framework/source/dispatch/windowcommanddispatch.cxx | 194 |
16 files changed, 5467 insertions, 0 deletions
diff --git a/framework/source/dispatch/closedispatcher.cxx b/framework/source/dispatch/closedispatcher.cxx new file mode 100644 index 000000000000..15b44aad0430 --- /dev/null +++ b/framework/source/dispatch/closedispatcher.cxx @@ -0,0 +1,656 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_______________________________________________ +// my own includes +#include <dispatch/closedispatcher.hxx> +#include <pattern/frame.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <classes/framelistanalyzer.hxx> +#include <services.h> +#include <general.h> + +//_______________________________________________ +// interface includes +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/CommandGroup.hpp> +#include <com/sun/star/lang/DisposedException.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include <com/sun/star/document/XActionLockable.hpp> +#include "com/sun/star/beans/XFastPropertySet.hpp" +#include <toolkit/helper/vclunohelper.hxx> + +//_______________________________________________ +// includes of other projects + +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <unotools/moduleoptions.hxx> + +//_______________________________________________ +// namespace + +namespace framework{ + +#ifdef fpf + #error "Who uses \"fpf\" as define. It will overwrite my namespace alias ..." +#endif +namespace fpf = ::framework::pattern::frame; + +//_______________________________________________ +// non exported const + +static ::rtl::OUString URL_CLOSEDOC = DECLARE_ASCII(".uno:CloseDoc" ); +static ::rtl::OUString URL_CLOSEWIN = DECLARE_ASCII(".uno:CloseWin" ); +static ::rtl::OUString URL_CLOSEFRAME = DECLARE_ASCII(".uno:CloseFrame"); + +//_______________________________________________ +// declarations + +DEFINE_XINTERFACE_4(CloseDispatcher , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::frame::XNotifyingDispatch ), + DIRECT_INTERFACE(css::frame::XDispatch ), + DIRECT_INTERFACE(css::frame::XDispatchInformationProvider)) + +// Note: XStatusListener is an implementation detail. Hide it for scripting! +DEFINE_XTYPEPROVIDER_4(CloseDispatcher , + css::lang::XTypeProvider , + css::frame::XDispatchInformationProvider, + css::frame::XNotifyingDispatch , + css::frame::XDispatch ) + +//----------------------------------------------- +CloseDispatcher::CloseDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame , + const ::rtl::OUString& sTarget) + : ThreadHelpBase (&Application::GetSolarMutex() ) + , ::cppu::OWeakObject( ) + , m_xSMGR (xSMGR ) + , m_aAsyncCallback (LINK( this, CloseDispatcher, impl_asyncCallback)) + , m_lStatusListener (m_aLock.getShareableOslMutex() ) +{ + m_xCloseFrame = CloseDispatcher::static_impl_searchRightTargetFrame(xFrame, sTarget); +} + +//----------------------------------------------- +CloseDispatcher::~CloseDispatcher() +{ +} + +//----------------------------------------------- +void SAL_CALL CloseDispatcher::dispatch(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments) + throw(css::uno::RuntimeException) +{ + dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >()); +} + +//----------------------------------------------- +css::uno::Sequence< sal_Int16 > SAL_CALL CloseDispatcher::getSupportedCommandGroups() + throw(css::uno::RuntimeException) +{ + css::uno::Sequence< sal_Int16 > lGroups(2); + lGroups[0] = css::frame::CommandGroup::VIEW; + lGroups[1] = css::frame::CommandGroup::DOCUMENT; + return lGroups; +} + +//----------------------------------------------- +css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL CloseDispatcher::getConfigurableDispatchInformation(sal_Int16 nCommandGroup) + throw(css::uno::RuntimeException) +{ + if (nCommandGroup == css::frame::CommandGroup::VIEW) + { + /* Attention: Dont add .uno:CloseFrame here. Because its not realy + a configurable feature ... and further it does not have + a valid UIName entry inside the GenericCommands.xcu ... */ + css::uno::Sequence< css::frame::DispatchInformation > lViewInfos(1); + lViewInfos[0].Command = URL_CLOSEWIN; + lViewInfos[0].GroupId = css::frame::CommandGroup::VIEW; + return lViewInfos; + } + else + if (nCommandGroup == css::frame::CommandGroup::DOCUMENT) + { + css::uno::Sequence< css::frame::DispatchInformation > lDocInfos(1); + lDocInfos[0].Command = URL_CLOSEDOC; + lDocInfos[0].GroupId = css::frame::CommandGroup::DOCUMENT; + return lDocInfos; + } + + return css::uno::Sequence< css::frame::DispatchInformation >(); +} + +//----------------------------------------------- +void SAL_CALL CloseDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void SAL_CALL CloseDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void SAL_CALL CloseDispatcher::dispatchWithNotification(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) + throw(css::uno::RuntimeException) +{ + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + // This reference indicates, that we was already called before and + // our asynchronous process was not finished yet. + // We have to reject double calls. Otherwhise we risk, + // that we try to close an already closed resource ... + // And its no problem to do nothing then. The UI user will try it again, if + // non of these jobs was successfully. + if (m_xSelfHold.is()) + { + aWriteLock.unlock(); + // <- SAFE ------------------------------ + + implts_notifyResultListener( + xListener, + css::frame::DispatchResultState::DONTKNOW, + css::uno::Any()); + return; + } + + // First we have to check, if this dispatcher is used right. Means if valid URLs are used. + // If not - we have to break this operation. But an optional listener must be informed. + // BTW: We save the information about the requested operation. Because + // we need it later. + if (aURL.Complete.equals(URL_CLOSEDOC)) + m_eOperation = E_CLOSE_DOC; + else + if (aURL.Complete.equals(URL_CLOSEWIN)) + m_eOperation = E_CLOSE_WIN; + else + if (aURL.Complete.equals(URL_CLOSEFRAME)) + m_eOperation = E_CLOSE_FRAME; + else + { + aWriteLock.unlock(); + // <- SAFE ------------------------------ + + implts_notifyResultListener( + xListener, + css::frame::DispatchResultState::FAILURE, + css::uno::Any()); + return; + } + + // OK - URLs are the right ones. + // But we cant execute synchronously :-) + // May we are called from a generic key-input handler, + // which isnt aware that this call kill its own environment ... + // Do it asynchronous everytimes! + + // But dont forget to hold usself alive. + // We are called back from an environment, which doesnt know an uno reference. + // They call us back by using our c++ interface. + + m_xResultListener = xListener; + m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + sal_Bool bIsSynchron = sal_False; + for (sal_Int32 nArgs=0; nArgs<lArguments.getLength(); nArgs++ ) + { + if ( lArguments[nArgs].Name.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM("SynchronMode")) ) + { + lArguments[nArgs].Value >>= bIsSynchron; + break; + } + } + + if ( bIsSynchron ) + impl_asyncCallback(0); + else + m_aAsyncCallback.Post(0); +} + +//----------------------------------------------- +/** + @short asynchronous callback + @descr We start all actions inside this object asnychronoue. + (see comments there). + Now we do the following: + - close all views to the same document, if needed and possible + - make the current frame empty + ! This step is neccessary to handle errors during closing the + document inside the frame. May the document shows a dialog and + the user ignore it. Then the state of the office can be changed + during we try to close frame and document. + - check the environment (menas count open frames - exlcuding our + current one) + - decide then, if we must close this frame only, establish the backing mode + or shutdown the whole application. +*/ +IMPL_LINK( CloseDispatcher, impl_asyncCallback, void*, EMPTYARG ) +{ + try + { + + // Allow calling of XController->suspend() everytimes. + // Dispatch is an UI functionality. We implement such dispatch object here. + // And further XController->suspend() was designed to bring an UI ... + sal_Bool bAllowSuspend = sal_True; + sal_Bool bControllerSuspended = sal_False; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + // Closing of all views, related to the same document, is allowed + // only if the dispatched URL was ".uno:CloseDoc"! + sal_Bool bCloseAllViewsToo = (m_eOperation == E_CLOSE_DOC); + + // BTW: Make some copies, which are needed later ... + EOperation eOperation = m_eOperation; + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + css::uno::Reference< css::frame::XFrame > xCloseFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchResultListener > xListener = m_xResultListener; + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // frame already dead ?! + // Nothing to do ! + if (! xCloseFrame.is()) + return 0; + + sal_Bool bCloseFrame = sal_False; + sal_Bool bEstablishBackingMode = sal_False; + sal_Bool bTerminateApp = sal_False; + + // Analyze the environment a first time. + // If we found some special cases, we can + // make some decisions erliar! + css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW); + FrameListAnalyzer aCheck1(xDesktop, xCloseFrame, FrameListAnalyzer::E_HELP | FrameListAnalyzer::E_BACKINGCOMPONENT); + + // a) If the curent frame (where the close dispatch was requested for) does not have + // any parent frame ... it will close this frame only. Such frame isnt part of the + // global desktop tree ... and such frames are used as "implementation details" only. + // E.g. the live previews of our wizards doing such things. And then the owner of the frame + // is responsible for closing the application or accepting closing of the application + // by others. + if ( ! xCloseFrame->getCreator().is()) + bCloseFrame = sal_True; + else + + // b) The help window cant disagree with any request. + // Because it doesnt implement a controller - it uses a window only. + // Further t cant be the last open frame - if we do all other things + // right inside this CloseDispatcher implementation. + // => close it! + if (aCheck1.m_bReferenceIsHelp) + bCloseFrame = sal_True; + else + + // c) If we are already in "backing mode", we have to terminate + // the application, if this special frame is closed. + // It doesnt matter, how many other frames (can be the help or hidden frames only) + // are open then. + // => terminate the application! + if (aCheck1.m_bReferenceIsBacking) + bTerminateApp = sal_True; + else + + // d) Otherwhise we have to: close all views to the same document, close the + // document inside our own frame and decide then again, what has to be done! + { + if (implts_prepareFrameForClosing(m_xCloseFrame, bAllowSuspend, bCloseAllViewsToo, bControllerSuspended)) + { + // OK; this frame is empty now. + // Check the environment again to decide, what is the next step. + FrameListAnalyzer aCheck2(xDesktop, xCloseFrame, FrameListAnalyzer::E_ALL); + + // c1) there is as minimum 1 frame open, which is visible and contains a document + // different from our one. And its not the help! + // => close our frame only - nothing else. + if (aCheck2.m_lOtherVisibleFrames.getLength()>0) + bCloseFrame = sal_True; + else + + // c2) if we close the current view ... but not all other views + // to the same document, we must close the current frame only! + // Because implts_closeView() suspended this view only - does not + // close the frame. + if ( + (!bCloseAllViewsToo ) && + (aCheck2.m_lModelFrames.getLength() > 0) + ) + bCloseFrame = sal_True; + + else + // c3) there is no other (visible) frame open ... + // The help module will be ignored everytimes! + // But we have to decide if we must terminate the + // application or establish the backing mode now. + // And that depends from the dispatched URL ... + { + if (eOperation == E_CLOSE_FRAME) + bTerminateApp = sal_True; + else if( SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE) ) + bEstablishBackingMode = sal_True; + else + bTerminateApp = sal_True; + } + } + } + + // Do it now ... + sal_Bool bSuccess = sal_False; + if (bCloseFrame) + bSuccess = implts_closeFrame(); + else + if (bEstablishBackingMode) + #if defined QUARTZ + { + // on mac close down, quickstarter keeps the process alive + // however if someone has shut down the quickstarter + // behave as any other platform + + bool bQuickstarterRunning = false; + // get quickstart service + try + { + css::uno::Reference< css::beans::XFastPropertySet > xSet( xSMGR->createInstance(IMPLEMENTATIONNAME_QUICKLAUNCHER), css::uno::UNO_QUERY_THROW ); + if( xSet.is() ) + { + css::uno::Any aVal( xSet->getFastPropertyValue( 0 ) ); + sal_Bool bState = sal_False; + if( aVal >>= bState ) + bQuickstarterRunning = bState; + } + } + catch( css::uno::Exception& ) + { + } + bSuccess = bQuickstarterRunning ? implts_terminateApplication() : implts_establishBackingMode(); + } + #else + bSuccess = implts_establishBackingMode(); + #endif + else + if (bTerminateApp) + bSuccess = implts_terminateApplication(); + + if ( + ( ! bSuccess ) && + ( bControllerSuspended ) + ) + { + css::uno::Reference< css::frame::XController > xController = xCloseFrame->getController(); + if (xController.is()) + xController->suspend(sal_False); + } + + // inform listener + sal_Int16 nState = css::frame::DispatchResultState::FAILURE; + if (bSuccess) + nState = css::frame::DispatchResultState::SUCCESS; + implts_notifyResultListener(xListener, nState, css::uno::Any()); + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + + // This method was called asynchronous from our main thread by using a pointer. + // We reached this method only, by using a reference to ourself :-) + // Further this member is used to detect still running and not yet finished + // ansynchronous operations. So its time now to release this reference. + // But hold it temp alive. Otherwhise we die before we can finish this method realy :-)) + css::uno::Reference< css::uno::XInterface > xTempHold = m_xSelfHold; + m_xSelfHold.clear(); + m_xResultListener.clear(); + + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + } + catch(const css::lang::DisposedException&) + { + LOG_ERROR("CloseDispatcher::impl_asyncCallback", "Congratulation! You found the reason for bug #120310#. Please contact the right developer and show him a scenario, which trigger this bug. THX.") + } + + return 0; +} + +//----------------------------------------------- +sal_Bool CloseDispatcher::implts_prepareFrameForClosing(const css::uno::Reference< css::frame::XFrame >& xFrame , + sal_Bool bAllowSuspend , + sal_Bool bCloseAllOtherViewsToo, + sal_Bool& bControllerSuspended ) +{ + // Frame already dead ... so this view is closed ... is closed ... is ... .-) + if (! xFrame.is()) + return sal_True; + + // Close all views to the same document ... if forced to do so. + // But dont touch our own frame here! + // We must do so ... because the may be following controller->suspend() + // will show the "save/discard/cancel" dialog for the last view only! + if (bCloseAllOtherViewsToo) + { + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::frame::XFramesSupplier > xDesktop(xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW); + FrameListAnalyzer aCheck(xDesktop, xFrame, FrameListAnalyzer::E_ALL); + + sal_Int32 c = aCheck.m_lModelFrames.getLength(); + sal_Int32 i = 0; + for (i=0; i<c; ++i) + { + if (!fpf::closeIt(aCheck.m_lModelFrames[i], sal_False)) + return sal_False; + } + } + + // If allowed - inform user about modified documents or + // still running jobs (e.g. printing). + if (bAllowSuspend) + { + css::uno::Reference< css::frame::XController > xController = xFrame->getController(); + if (xController.is()) // some views dont uses a controller .-( (e.g. the help window) + { + bControllerSuspended = xController->suspend(sal_True); + if (! bControllerSuspended) + return sal_False; + } + } + + // dont remove the component realy by e.g. calling setComponent(null, null). + // It's enough to suspend the controller. + // If we close the frame later this controller doesnt show the same dialog again. + return sal_True; +} + +//----------------------------------------------- +sal_Bool CloseDispatcher::implts_closeFrame() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::frame::XFrame > xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY); + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + // frame already dead ? => so it's closed ... it's closed ... + if ( ! xFrame.is() ) + return sal_True; + + // dont deliver owner ship; our "UI user" will try it again if it failed. + // OK - he will get an empty frame then. But normaly an empty frame + // should be closeable always :-) + if (!fpf::closeIt(xFrame, sal_False)) + return sal_False; + + // SAFE -> ---------------------------------- + WriteGuard aWriteLock(m_aLock); + m_xCloseFrame = css::uno::WeakReference< css::frame::XFrame >(); + aWriteLock.unlock(); + // <- SAFE ---------------------------------- + + return sal_True; +} + +//----------------------------------------------- +sal_Bool CloseDispatcher::implts_establishBackingMode() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + css::uno::Reference< css::frame::XFrame > xFrame (m_xCloseFrame.get(), css::uno::UNO_QUERY); + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + if (!xFrame.is()) + return sal_False; + + css::uno::Reference < css::document::XActionLockable > xLock( xFrame, css::uno::UNO_QUERY ); + if ( xLock.is() && xLock->isActionLocked() ) + return sal_False; + + css::uno::Reference< css::awt::XWindow > xContainerWindow = xFrame->getContainerWindow(); + css::uno::Sequence< css::uno::Any > lArgs(1); + lArgs[0] <<= xContainerWindow; + + css::uno::Reference< css::frame::XController > xBackingComp( + xSMGR->createInstanceWithArguments(SERVICENAME_STARTMODULE, lArgs), + css::uno::UNO_QUERY_THROW); + + // Attention: You MUST(!) call setComponent() before you call attachFrame(). + css::uno::Reference< css::awt::XWindow > xBackingWin(xBackingComp, css::uno::UNO_QUERY); + xFrame->setComponent(xBackingWin, xBackingComp); + xBackingComp->attachFrame(xFrame); + xContainerWindow->setVisible(sal_True); + + return sal_True; +} + +//----------------------------------------------- +sal_Bool CloseDispatcher::implts_terminateApplication() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::frame::XDesktop > xDesktop( + xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY_THROW); + + return xDesktop->terminate(); +} + +//----------------------------------------------- +void CloseDispatcher::implts_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener, + sal_Int16 nState , + const css::uno::Any& aResult ) +{ + if (!xListener.is()) + return; + + css::frame::DispatchResultEvent aEvent( + css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY), + nState, + aResult); + + xListener->dispatchFinished(aEvent); +} + +//----------------------------------------------- +css::uno::Reference< css::frame::XFrame > CloseDispatcher::static_impl_searchRightTargetFrame(const css::uno::Reference< css::frame::XFrame >& xFrame , + const ::rtl::OUString& sTarget) +{ + if (sTarget.equalsIgnoreAsciiCaseAscii("_self")) + return xFrame; + + OSL_ENSURE((sTarget.getLength() < 1), "CloseDispatch used for unexpected target. Magic things will happen now .-)"); + + css::uno::Reference< css::frame::XFrame > xTarget = xFrame; + while(sal_True) + { + // a) top frames wil be closed + if (xTarget->isTop()) + return xTarget; + + // b) even child frame containing top level windows (e.g. query designer of database) will be closed + css::uno::Reference< css::awt::XWindow > xWindow = xTarget->getContainerWindow(); + css::uno::Reference< css::awt::XTopWindow > xTopWindowCheck(xWindow, css::uno::UNO_QUERY); + if (xTopWindowCheck.is()) + { + // b1) Note: Toolkit interface XTopWindow sometimes is used by real VCL-child-windows also .-) + // Be sure that these window is realy a "top system window". + // Attention ! Checking Window->GetParent() isnt the right approach here. + // Because sometimes VCL create "implicit border windows" as parents even we created + // a simple XWindow using the toolkit only .-( + SolarMutexGuard aSolarLock; + Window* pWindow = VCLUnoHelper::GetWindow( xWindow ); + if ( + (pWindow ) && + (pWindow->IsSystemWindow()) + ) + return xTarget; + } + + // c) try to find better results on parent frame + // If no parent frame exists (because this frame is used outside the desktop tree) + // the given frame must be used directly. + css::uno::Reference< css::frame::XFrame > xParent(xTarget->getCreator(), css::uno::UNO_QUERY); + if ( ! xParent.is()) + return xTarget; + + // c1) check parent frame inside next loop ... + xTarget = xParent; + } +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/dispatchinformationprovider.cxx b/framework/source/dispatch/dispatchinformationprovider.cxx new file mode 100644 index 000000000000..bef585ed6ab5 --- /dev/null +++ b/framework/source/dispatch/dispatchinformationprovider.cxx @@ -0,0 +1,193 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/dispatchinformationprovider.hxx> +#include <dispatch/closedispatcher.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <stdtypes.h> +#include <services.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/frame/CommandGroup.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ +#include <comphelper/sequenceasvector.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +namespace css = ::com::sun::star; + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ +DEFINE_XINTERFACE_1(DispatchInformationProvider , + OWeakObject , + DIRECT_INTERFACE(css::frame::XDispatchInformationProvider)) + +//_________________________________________________________________________________________________________________ +DispatchInformationProvider::DispatchInformationProvider(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame) + : ThreadHelpBase(&Application::GetSolarMutex()) + , m_xSMGR (xSMGR ) + , m_xFrame (xFrame ) +{ +} + +//_________________________________________________________________________________________________________________ +DispatchInformationProvider::~DispatchInformationProvider() +{ +} + +//_________________________________________________________________________________________________________________ +css::uno::Sequence< sal_Int16 > SAL_CALL DispatchInformationProvider::getSupportedCommandGroups() + throw (css::uno::RuntimeException) +{ + css::uno::Sequence< css::uno::Reference< css::frame::XDispatchInformationProvider > > lProvider = implts_getAllSubProvider(); + sal_Int32 c1 = lProvider.getLength(); + sal_Int32 i1 = 0; + + ::comphelper::SequenceAsVector< sal_Int16 > lGroups; + + for (i1=0; i1<c1; ++i1) + { + // ignore controller, which doesnt implement the right interface + css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider = lProvider[i1]; + if (!xProvider.is()) + continue; + + const css::uno::Sequence< sal_Int16 > lProviderGroups = xProvider->getSupportedCommandGroups(); + sal_Int32 c2 = lProviderGroups.getLength(); + sal_Int32 i2 = 0; + for (i2=0; i2<c2; ++i2) + { + const sal_Int16& rGroup = lProviderGroups[i2]; + ::comphelper::SequenceAsVector< sal_Int16 >::const_iterator pGroup = ::std::find(lGroups.begin(), lGroups.end(), rGroup); + if (pGroup == lGroups.end()) + lGroups.push_back(rGroup); + } + } + + return lGroups.getAsConstList(); +} + +//_________________________________________________________________________________________________________________ +css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL DispatchInformationProvider::getConfigurableDispatchInformation(sal_Int16 nCommandGroup) + throw (css::uno::RuntimeException) +{ + css::uno::Sequence< css::uno::Reference< css::frame::XDispatchInformationProvider > > lProvider = implts_getAllSubProvider(); + sal_Int32 c1 = lProvider.getLength(); + sal_Int32 i1 = 0; + + BaseHash< css::frame::DispatchInformation > lInfos; + + for (i1=0; i1<c1; ++i1) + { + try + { + // ignore controller, which doesnt implement the right interface + css::uno::Reference< css::frame::XDispatchInformationProvider > xProvider = lProvider[i1]; + if (!xProvider.is()) + continue; + + const css::uno::Sequence< css::frame::DispatchInformation > lProviderInfos = xProvider->getConfigurableDispatchInformation(nCommandGroup); + sal_Int32 c2 = lProviderInfos.getLength(); + sal_Int32 i2 = 0; + for (i2=0; i2<c2; ++i2) + { + const css::frame::DispatchInformation& rInfo = lProviderInfos[i2]; + BaseHash< css::frame::DispatchInformation >::const_iterator pInfo = lInfos.find(rInfo.Command); + if (pInfo == lInfos.end()) + lInfos[rInfo.Command] = rInfo; + } + } + catch(const css::uno::RuntimeException& exRun) + { throw exRun; } + catch(const css::uno::Exception&) + { continue; } + } + + c1 = (sal_Int32)lInfos.size(); + i1 = 0; + + css::uno::Sequence< css::frame::DispatchInformation > lReturn(c1); + BaseHash< css::frame::DispatchInformation >::const_iterator pStepp ; + for ( pStepp = lInfos.begin() ; + pStepp != lInfos.end () && i1<c1 ; + ++pStepp, ++i1 ) + { + lReturn[i1] = pStepp->second; + } + return lReturn; +} + +//_________________________________________________________________________________________________________________ +css::uno::Sequence< css::uno::Reference< css::frame::XDispatchInformationProvider > > DispatchInformationProvider::implts_getAllSubProvider() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + css::uno::Reference< css::frame::XFrame > xFrame(m_xFrame.get(), css::uno::UNO_QUERY); + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + if (!xFrame.is()) + return css::uno::Sequence< css::uno::Reference< css::frame::XDispatchInformationProvider > >(); + + CloseDispatcher* pCloser = new CloseDispatcher(xSMGR, xFrame, ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("_self"))); // explicit "_self" ... not "" ... see implementation of close dispatcher itself! + css::uno::Reference< css::uno::XInterface > xCloser(static_cast< css::frame::XDispatch* >(pCloser), css::uno::UNO_QUERY); + + css::uno::Reference< css::frame::XDispatchInformationProvider > xCloseDispatch(xCloser , css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchInformationProvider > xController (xFrame->getController() , css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchInformationProvider > xAppDispatcher(xSMGR->createInstance(IMPLEMENTATIONNAME_APPDISPATCHPROVIDER), css::uno::UNO_QUERY); + + css::uno::Sequence< css::uno::Reference< css::frame::XDispatchInformationProvider > > lProvider(3); + lProvider[0] = xController ; + lProvider[1] = xCloseDispatch; + lProvider[2] = xAppDispatcher; + + return lProvider; +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/dispatchprovider.cxx b/framework/source/dispatch/dispatchprovider.cxx new file mode 100644 index 000000000000..1b1bfc263335 --- /dev/null +++ b/framework/source/dispatch/dispatchprovider.cxx @@ -0,0 +1,798 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ + +#include <stdio.h> +#include <dispatch/dispatchprovider.hxx> +#include <loadenv/loadenv.hxx> +#include <dispatch/loaddispatcher.hxx> +#include <dispatch/closedispatcher.hxx> +#include <dispatch/menudispatcher.hxx> +#include <dispatch/helpagentdispatcher.hxx> +#include <dispatch/startmoduledispatcher.hxx> + +#include <pattern/window.hxx> +#include <threadhelp/transactionguard.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <dispatchcommands.h> +#include <protocols.h> +#include <services.h> +#include <targets.h> +#include <general.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/uno/Exception.hpp> +#include <com/sun/star/ucb/XContentProviderManager.hpp> +#include <com/sun/star/document/XTypeDetection.hpp> +#include <com/sun/star/lang/XInitialization.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ +#include <osl/diagnose.h> +#include <rtl/string.h> +#include <rtl/ustring.hxx> +#include <vcl/svapp.hxx> +#include <rtl/ustrbuf.hxx> +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//***************************************************************************************************************** +// XInterface, XTypeProvider +//***************************************************************************************************************** +DEFINE_XINTERFACE_2( DispatchProvider , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::frame::XDispatchProvider) + ) + +DEFINE_XTYPEPROVIDER_2( DispatchProvider , + css::lang::XTypeProvider , + css::frame::XDispatchProvider + ) + +//_________________________________________________________________________________________________________________ + +/** + @short standard ctor/dtor + @descr These initialize a new instance of tihs class with needed informations for work. + We hold a weakreference to our owner frame which start dispatches at us. + We can't use a normal reference because he hold a reference of us too ... + nobody can die so ...! + + @seealso using at owner + + @param xFactory + reference to servicemanager to create new services. + @param xFrame + reference to our owner frame. + + @modified 17.05.2002 10:07, as96863 +*/ +DispatchProvider::DispatchProvider( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory , + const css::uno::Reference< css::frame::XFrame >& xFrame ) + // Init baseclasses first + : ThreadHelpBase( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) + , m_xFrame ( xFrame ) +{ +} + +//_________________________________________________________________________________________________________________ + +/** + @short protected(!) dtor for deinitializing + @descr We made it protected to prevent using of us as base class instead as a member. + + @modified 17.05.2002 10:05, as96863 + */ +DispatchProvider::~DispatchProvider() +{ +} + +//_________________________________________________________________________________________________________________ + +/** + @interface XDispatchProvider + @short search a dispatcher for given URL + @descr If no interceptor is set on owner, we search for right frame and dispatch URL to it. + If no frame was found, we do nothing. + But we doesn't do it directly here. We detect the type of our owner frame and calls + specialized queryDispatch() helper dependen from that. Because a Desktop handle some + requests in another way then a normal frame. + + @param aURL + URL to dispatch. + @param sTargetFrameName + name of searched frame. + @param nSearchFlags + flags for searching. + @return A reference to a dispatch object for this URL (if someone was found!). + + @threadsafe yes + @modified 17.05.2002 10:59, as96863 +*/ +css::uno::Reference< css::frame::XDispatch > SAL_CALL DispatchProvider::queryDispatch( const css::util::URL& aURL , + const ::rtl::OUString& sTargetFrameName , + sal_Int32 nSearchFlags ) throw( css::uno::RuntimeException ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + + /* SAFE { */ + ReadGuard aReadLock( m_aLock ); + css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY ); + aReadLock.unlock(); + /* } SAFE */ + + css::uno::Reference< css::frame::XDesktop > xDesktopCheck( xOwner, css::uno::UNO_QUERY ); + + if (xDesktopCheck.is()) + xDispatcher = implts_queryDesktopDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags); + else + xDispatcher = implts_queryFrameDispatch(xOwner, aURL, sTargetFrameName, nSearchFlags); + + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @interface XDispatchProvider + @short do the same like queryDispatch() ... but handle multiple dispatches at the same time + @descr It's an optimism. User give us a list of queries ... and we return a list of dispatcher. + If one of given queries couldn't be solved to a real existing dispatcher ... + we return a list with empty references in it! Order of both lists will be retained! + + @seealso method queryDispatch() + + @param lDescriptions + a list of all dispatch parameters for multiple requests + @return A reference a list of dispatch objects for these URLs - may with some <NULL/> values inside. + + @threadsafe yes + @modified 17.05.2002 09:55, as96863 +*/ +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL DispatchProvider::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptions ) throw( css::uno::RuntimeException ) +{ + // Create return list - which must have same size then the given descriptor + // It's not allowed to pack it! + sal_Int32 nCount = lDescriptions.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); + + // Step over all descriptors and try to get any dispatcher for it. + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = queryDispatch( lDescriptions[i].FeatureURL , + lDescriptions[i].FrameName , + lDescriptions[i].SearchFlags ); + } + + return lDispatcher; +} + +//_________________________________________________________________________________________________________________ + +::sal_Bool lcl_isStartModuleDispatch (const css::util::URL& aURL) +{ + return (aURL.Complete.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(CMD_UNO_SHOWSTARTMODULE))); +} + +//_________________________________________________________________________________________________________________ + +/** + @short helper for queryDispatch() + @descr Every member of the frame tree (frame, desktop) must handle such request + in another way. So we implement different specialized metods for every one. + + @threadsafe yes + @modified 20.08.2003 08:32, as96863 + */ +css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryDesktopDispatch( const css::uno::Reference< css::frame::XFrame > xDesktop , + const css::util::URL& aURL , + const ::rtl::OUString& sTargetFrameName , + sal_Int32 nSearchFlags ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + + // ignore wrong requests which are not supported + if ( + (sTargetFrameName==SPECIALTARGET_MENUBAR ) || // valid for frame dispatches - not for desktop + (sTargetFrameName==SPECIALTARGET_HELPAGENT) || // valid for frame dispatches - not for desktop + (sTargetFrameName==SPECIALTARGET_PARENT ) || // we have no parent by definition + (sTargetFrameName==SPECIALTARGET_BEAMER ) // beamer frames are allowed as child of tasks only - + // and they exist more then ones. We have no idea which our sub tasks is the right one + ) + { + return NULL; + } + + //----------------------------------------------------------------------------------------------------- + // I) handle special cases which not right for using findFrame() first + //----------------------------------------------------------------------------------------------------- + + //----------------------------------------------------------------------------------------------------- + // I.I) "_blank" + // It's not the right place to create a new task here - because we are queried for a dispatch object + // only, which can handle such request. Such dispatcher should create the required task on demand. + // Normaly the functionality for "_blank" is provided by findFrame() - but that would create it directly + // here. Thats why we must "intercept" here. + //----------------------------------------------------------------------------------------------------- + if (sTargetFrameName==SPECIALTARGET_BLANK) + { + if (implts_isLoadableContent(aURL)) + xDispatcher = implts_getOrCreateDispatchHelper( E_BLANKDISPATCHER, xDesktop ); + } + + //----------------------------------------------------------------------------------------------------- + // I.II) "_default" + // This is a combination of search an empty task for recycling - or create a new one. + //----------------------------------------------------------------------------------------------------- + else + if (sTargetFrameName==SPECIALTARGET_DEFAULT) + { + if (implts_isLoadableContent(aURL)) + xDispatcher = implts_getOrCreateDispatchHelper( E_DEFAULTDISPATCHER, xDesktop ); + + if (lcl_isStartModuleDispatch(aURL)) + xDispatcher = implts_getOrCreateDispatchHelper( E_STARTMODULEDISPATCHER, xDesktop ); + } + + //----------------------------------------------------------------------------------------------------- + // I.III) "_self", "", "_top" + // The desktop can't load any document - but he can handle some special protocols like "uno", "slot" ... + // Why is "top" here handled too? Because the desktop is the topest frame. Normaly it's superflous + // to use this target - but we can handle it in the same manner then "_self". + //----------------------------------------------------------------------------------------------------- + else + if ( + (sTargetFrameName==SPECIALTARGET_SELF) || + (sTargetFrameName==SPECIALTARGET_TOP ) || + (sTargetFrameName.getLength()<1 ) + ) + { + xDispatcher = implts_searchProtocolHandler(aURL); + } + + //----------------------------------------------------------------------------------------------------- + // I.IV) no further special targets exist + // Now we have to search for the right target frame by calling findFrame() - but should provide our code + // against creation of a new task if no frame could be found. + // I said it b efore - it's allowed for dispatch() only. + //----------------------------------------------------------------------------------------------------- + else + { + sal_Int32 nRightFlags = nSearchFlags; + nRightFlags &= ~css::frame::FrameSearchFlag::CREATE; + + // try to find any existing target and ask him for his dispatcher + css::uno::Reference< css::frame::XFrame > xFoundFrame = xDesktop->findFrame(sTargetFrameName, nRightFlags); + if (xFoundFrame.is()) + { + css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY ); + xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0); + } + else + // if it couldn't be found - but creation was allowed + // use special dispatcher for creatio or froward it to the browser + if (nSearchFlags & css::frame::FrameSearchFlag::CREATE) + xDispatcher = implts_getOrCreateDispatchHelper( E_CREATEDISPATCHER, xDesktop, sTargetFrameName, nSearchFlags ); + } + + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_queryFrameDispatch( const css::uno::Reference< css::frame::XFrame > xFrame , + const css::util::URL& aURL , + const ::rtl::OUString& sTargetFrameName , + sal_Int32 nSearchFlags ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + + //----------------------------------------------------------------------------------------------------- + // 0) Some URLs are dispatched in a generic way (e.g. by the menu) using the default target "". + // But they are specified to use her own fix target. Detect such URLs here and use the correct target. + //----------------------------------------------------------------------------------------------------- + + ::rtl::OUString sTargetName = sTargetFrameName; + + //----------------------------------------------------------------------------------------------------- + // I) handle special cases which not right for using findFrame() first + //----------------------------------------------------------------------------------------------------- + + //----------------------------------------------------------------------------------------------------- + // I.I) "_blank", "_default" + // It's not the right place to create a new task here. Only the desktop can do that. + // Normaly the functionality for "_blank" is provided by findFrame() - but that would create it directly + // here. Thats why we must "intercept" here. + //----------------------------------------------------------------------------------------------------- + if ( + (sTargetName==SPECIALTARGET_BLANK ) || + (sTargetName==SPECIALTARGET_DEFAULT) + ) + { + css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); + if (xParent.is()) + xDispatcher = xParent->queryDispatch(aURL, sTargetName, 0); // its a special target - ignore search flags + } + + //----------------------------------------------------------------------------------------------------- + // I.II) "_menubar" + // Special mode on frame or task to receive the local menu. Not supported by findFrame() + //----------------------------------------------------------------------------------------------------- + else + if (sTargetName==SPECIALTARGET_MENUBAR) + { + xDispatcher = implts_getOrCreateDispatchHelper( E_MENUDISPATCHER, xFrame ); + } + + //----------------------------------------------------------------------------------------------------- + // I.III) "_helpagent" + // Special mode on frame or task to start the help agent. + // It's defined for top level frames only. + //----------------------------------------------------------------------------------------------------- + else + if (sTargetName==SPECIALTARGET_HELPAGENT) + { + if (WindowHelper::isTopWindow(xFrame->getContainerWindow())) + xDispatcher = implts_getOrCreateDispatchHelper( E_HELPAGENTDISPATCHER, xFrame ); + else + { + // Don''t use findFrame() here - because it's not possible to find + // a top lebel frame without knowing his name. And a frame with name + // "" can't be realy searched! That's why forward query to any parent + // explicitly. + css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFrame->getCreator(), css::uno::UNO_QUERY ); + if (xProvider.is()) + xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_HELPAGENT,0); + } + } + + //----------------------------------------------------------------------------------------------------- + // I.IV) "_helpagent" + // Special sub frame of a top frame only. Search or create it. ... OK it's currently a little bit HACKI. + // Only the sfx (means the controller) can create it it. + //----------------------------------------------------------------------------------------------------- + else + if (sTargetName==SPECIALTARGET_BEAMER) + { + css::uno::Reference< css::frame::XDispatchProvider > xBeamer( xFrame->findFrame( SPECIALTARGET_BEAMER, css::frame::FrameSearchFlag::CHILDREN | css::frame::FrameSearchFlag::SELF ), css::uno::UNO_QUERY ); + if (xBeamer.is()) + { + xDispatcher = xBeamer->queryDispatch(aURL, SPECIALTARGET_SELF, 0); + } + else + { + css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY ); + if (xController.is()) + // force using of special target - but use original search flags + // May the caller used the CREATE flag or not! + xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_BEAMER, nSearchFlags); + } + } + + //----------------------------------------------------------------------------------------------------- + // I.V) "_parent" + // Our parent frame (if it exist) should handle this URL. + //----------------------------------------------------------------------------------------------------- + else + if (sTargetName==SPECIALTARGET_PARENT) + { + css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); + if (xParent.is()) + // SELF => we must adress the parent directly... and not his parent or any other parent! + xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0); + } + + //----------------------------------------------------------------------------------------------------- + // I.VI) "_top" + // This request must be forwarded to any parent frame, till we reach a top frame. + // If no parent exist, we can handle itself. + //----------------------------------------------------------------------------------------------------- + else + if (sTargetName==SPECIALTARGET_TOP) + { + if (xFrame->isTop()) + { + // If we are this top frame itself (means our owner frame) + // we should call ourself recursiv with a better target "_self". + // So we can share the same code! (see reaction for "_self" inside this method too.) + xDispatcher = this->queryDispatch(aURL,SPECIALTARGET_SELF,0); + } + else + { + css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); + // Normaly if isTop() returned FALSE ... the parent frame MUST(!) exist ... + // But it seams to be better to check that here to prevent us against an access violation. + if (xParent.is()) + xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_TOP, 0); + } + } + + //----------------------------------------------------------------------------------------------------- + // I.VII) "_self", "" + // Our owner frame should handle this URL. But we can't do it for all of them. + // So we ask the internal setted controller first. If he disagree we try to find a registered + // protocol handler. If this failed too - we check for a loadable content and in case of true + // we load it into the frame by returning specilized dispatch object. + //----------------------------------------------------------------------------------------------------- + else + if ( + (sTargetName==SPECIALTARGET_SELF) || + (sTargetName.getLength()<1 ) + ) + { + // There exist a hard coded interception for special URLs. + if ( + (aURL.Complete.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".uno:CloseDoc"))) || + (aURL.Complete.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".uno:CloseWin"))) + ) + { + css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); + // In case the frame is not a top one, is not based on system window and has a parent, + // the parent frame should to be queried for the correct dispatcher. + // See i93473 + if ( + !WindowHelper::isTopWindow(xFrame->getContainerWindow()) && + !VCLUnoHelper::GetWindow(xFrame->getContainerWindow())->IsSystemWindow() && + xParent.is() + ) + xDispatcher = xParent->queryDispatch(aURL, SPECIALTARGET_SELF, 0); + else + xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame ); + } + else if (aURL.Complete.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(".uno:CloseFrame"))) + xDispatcher = implts_getOrCreateDispatchHelper( E_CLOSEDISPATCHER, xFrame ); + + if ( ! xDispatcher.is()) + { + // Ask our controller for his agreement for these dispatched URL ... + // because some URLs are internal and can be handled faster by SFX - which most is the current controller! + // But in case of e.g. the bibliography not all queries will be handled successfully here. + css::uno::Reference< css::frame::XDispatchProvider > xController( xFrame->getController(), css::uno::UNO_QUERY ); + if (xController.is()) + xDispatcher = xController->queryDispatch(aURL, SPECIALTARGET_SELF, 0); + } + + // If controller has no fun to dispatch these URL - we must search another right dispatcher. + // Search for any registered protocol handler first. + if (!xDispatcher.is()) + xDispatcher = implts_searchProtocolHandler(aURL); + + // Not for controller - not for protocol handler + // It should be a loadable content - may be a file. Check it ... + // This check is neccessary to found out, that + // support for some protocols isn't installed by user. May be + // "ftp" isn't available. So we suppress creation of our self dispatcher. + // The result will be clear. He can't handle it - but he would try it. + if ( + ( ! xDispatcher.is() ) && + ( implts_isLoadableContent(aURL) ) + ) + { + xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame ); + } + } + + //----------------------------------------------------------------------------------------------------- + // I.VI) no further special handlings exist + // Now we have to search for the right target frame by calling findFrame() - but should provide our code + // against creation of a new task if no frame could be found. + // I said it before - it's allowed for dispatch() only. + //----------------------------------------------------------------------------------------------------- + else + { + sal_Int32 nRightFlags = nSearchFlags; + nRightFlags &= ~css::frame::FrameSearchFlag::CREATE; + + // try to find any existing target and ask him for his dispatcher + css::uno::Reference< css::frame::XFrame > xFoundFrame = xFrame->findFrame(sTargetName, nRightFlags); + if (xFoundFrame.is()) + { + // Attention: Found target is our own owner frame! + // Don't ask him for his dispatcher. We know it already - it's our self dispatch helper. + // Otherwhise we can start a never ending recursiv call. Why? + // Somewere called our owner frame - he called some interceptor objects - and may by this dispatch provider + // is called. If wa use queryDispatch() on our owner frame again - we start this call stack again ... and again. + if (xFoundFrame==xFrame) + xDispatcher = implts_getOrCreateDispatchHelper( E_SELFDISPATCHER, xFrame ); + else + { + css::uno::Reference< css::frame::XDispatchProvider > xProvider( xFoundFrame, css::uno::UNO_QUERY ); + xDispatcher = xProvider->queryDispatch(aURL,SPECIALTARGET_SELF,0); + } + } + else + // if it couldn't be found - but creation was allowed + // forward request to the desktop. + // Note: The given target name must be used to set the name on new created task! + // Don't forward request by changing it to a special one e.g _blank. + // Use the CREATE flag only to prevent call against further searches. + // We already know it - the target must be created new. + if (nSearchFlags & css::frame::FrameSearchFlag::CREATE) + { + css::uno::Reference< css::frame::XDispatchProvider > xParent( xFrame->getCreator(), css::uno::UNO_QUERY ); + if (xParent.is()) + xDispatcher = xParent->queryDispatch(aURL, sTargetName, css::frame::FrameSearchFlag::CREATE); + } + } + + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short search for a registered protocol handler and ask him for a dispatch object + @descr Wes earch a suitable handler inside our cfg package org.openoffice.Office.ProtocolHandler. + If we found anyone, we create and initialize it. Initialize means: we set our owner frame on it + as context information. He can use it or leave it. Of course - we are aware of handler implementations, + which doesn't support initialization. It's an optional feature. + + @param aURL + the dispatch URL for which may a handler is registered + + @return A dispatch object if a handler was found and agree with the given URL or <NULL/> otherwhise. + + @threadsafe yes + @modified 05.09.2002 13:43, as96863 +*/ +css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_searchProtocolHandler( const css::util::URL& aURL ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + ProtocolHandler aHandler ; + + // This member is threadsafe by himself and lives if we live - we doesn't need any mutex here. + if (m_aProtocolHandlerCache.search(aURL,&aHandler)) + { + /* SAFE { */ + ReadGuard aReadLock( m_aLock ); + + // create it + css::uno::Reference< css::frame::XDispatchProvider > xHandler; + try + { + xHandler = css::uno::Reference< css::frame::XDispatchProvider >( + m_xFactory->createInstance(aHandler.m_sUNOName), + css::uno::UNO_QUERY); + } + catch(css::uno::Exception&) {} + + // look if initialization is neccessary + css::uno::Reference< css::lang::XInitialization > xInit( xHandler, css::uno::UNO_QUERY ); + if (xInit.is()) + { + css::uno::Reference< css::frame::XFrame > xOwner( m_xFrame.get(), css::uno::UNO_QUERY ); + LOG_ASSERT(xOwner.is(), "DispatchProvider::implts_searchProtocolHandler()\nCouldn't get reference to my owner frame. So I can't set may needed context information for this protocol handler.") + if (xOwner.is()) + { + try + { + // but do it only, if all context informations are OK + css::uno::Sequence< css::uno::Any > lContext(1); + lContext[0] <<= xOwner; + xInit->initialize(lContext); + } + catch(css::uno::Exception&) {} + } + } + + aReadLock.unlock(); + /* } SAFE */ + + // ask for his (sub)dispatcher for the given URL + if (xHandler.is()) + xDispatcher = xHandler->queryDispatch(aURL,SPECIALTARGET_SELF,0); + } + + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short get or create new dispatch helper + @descr Sometimes we need some helper implementations to support dispatching of special URLs or commands. + But it's not a good idea to hold these services for the whole life time of this provider instance. + We should create it on demand ... + Thats why we implement this method. It return an already existing helper or create a new one otherwise. + + @attention The parameter sTarget and nSearchFlags are defaulted to "" and 0! + Please use it only, if you can be shure, that the realy given by the outside calli! + Mostly it depends from the parameter eHelper is they are required or not. + + @param eHelper + specify the requested dispatch helper + @param xOwner + the target of possible dispatch() call on created dispatch helper + @param sTarget + the target parameter of the original queryDispatch() request + @param nSearchFlags + the flags parameter of the original queryDispatch() request + @return A reference to a dispatch helper. + + @threadsafe yes + @modified 20.08.2003 10:22, as96863 +*/ +css::uno::Reference< css::frame::XDispatch > DispatchProvider::implts_getOrCreateDispatchHelper( EDispatchHelper eHelper , + const css::uno::Reference< css::frame::XFrame >& xOwner , + const ::rtl::OUString& sTarget , + sal_Int32 nSearchFlags) +{ + css::uno::Reference< css::frame::XDispatch > xDispatchHelper; + + /* SAFE { */ + ReadGuard aReadLock( m_aLock ); + css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory; + aReadLock.unlock(); + /* } SAFE */ + + switch (eHelper) + { + case E_MENUDISPATCHER : + { + // Attention: Such menue dispatcher must be a singleton for this frame - means our owner frame. + // Otherwhise he can make some trouble. + /* SAFE { */ + WriteGuard aWriteLock( m_aLock ); + if ( ! m_xMenuDispatcher.is() ) + { + MenuDispatcher* pDispatcher = new MenuDispatcher( xFactory, xOwner ); + m_xMenuDispatcher = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + xDispatchHelper = m_xMenuDispatcher; + aWriteLock.unlock(); + /* } SAFE */ + } + break; + + case E_HELPAGENTDISPATCHER : + { + // Attention: It's not a good idea to create this help agent twice for the same frame (window) + // May it will be shown twice too - and user activate the first one. Then he get the corresponding + // help window ... but there exist another help agent window on bottom side of the frame window. + // It's superflous. Create it on demand - but hold it alive till this provider dies. + /* SAFE { */ + WriteGuard aWriteLock( m_aLock ); + if ( ! m_xHelpAgentDispatcher.is() ) + { + HelpAgentDispatcher* pDispatcher = new HelpAgentDispatcher( xOwner ); + m_xHelpAgentDispatcher = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + xDispatchHelper = m_xHelpAgentDispatcher; + aWriteLock.unlock(); + /* } SAFE */ + } + break; + + case E_CREATEDISPATCHER : + { + LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, sTarget, nSearchFlags); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + break; + + case E_BLANKDISPATCHER : + { + css::uno::Reference< css::frame::XFrame > xDesktop( xOwner, css::uno::UNO_QUERY ); + if (xDesktop.is()) + { + LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_BLANK, 0); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + } + break; + + case E_DEFAULTDISPATCHER : + { + css::uno::Reference< css::frame::XFrame > xDesktop( xOwner, css::uno::UNO_QUERY ); + if (xDesktop.is()) + { + LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_DEFAULT, 0); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + } + break; + + case E_SELFDISPATCHER : + { + LoadDispatcher* pDispatcher = new LoadDispatcher(xFactory, xOwner, SPECIALTARGET_SELF, 0); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + break; + + case E_CLOSEDISPATCHER : + { + CloseDispatcher* pDispatcher = new CloseDispatcher( xFactory, xOwner, sTarget ); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + break; + + case E_STARTMODULEDISPATCHER : + { + StartModuleDispatcher* pDispatcher = new StartModuleDispatcher( xFactory, xOwner, sTarget ); + xDispatchHelper = css::uno::Reference< css::frame::XDispatch >( static_cast< ::cppu::OWeakObject* >(pDispatcher), css::uno::UNO_QUERY ); + } + break; + } + + return xDispatchHelper; +} + +//_________________________________________________________________________________________________________________ + +/** + @short check URL for support by our used loader or handler + @descr If we must return our own dispatch helper implementations (self, blank, create dispatcher!) + we should be shure, that URL describe any loadable content. Otherwise slot/uno URLs + will be detected ... but there exist nothing for ral loading into a target frame! + + @param aURL + URL which should be "detected" + @return <TRUE/> if somewhere could handle that - <FALSE/> otherwise. + + @threadsafe yes + @modified 17.05.2002 09:47, as96863 +*/ +sal_Bool DispatchProvider::implts_isLoadableContent( const css::util::URL& aURL ) +{ + LoadEnv::EContentType eType = LoadEnv::classifyContent(aURL.Complete, css::uno::Sequence< css::beans::PropertyValue >()); + return ( eType == LoadEnv::E_CAN_BE_LOADED ); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/helpagentdispatcher.cxx b/framework/source/dispatch/helpagentdispatcher.cxx new file mode 100644 index 000000000000..4ae8ac15ee6f --- /dev/null +++ b/framework/source/dispatch/helpagentdispatcher.cxx @@ -0,0 +1,446 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +#include <dispatch/helpagentdispatcher.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <com/sun/star/awt/XWindow2.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/awt/Rectangle.hpp> +#include <toolkit/helper/vclunohelper.hxx> +#include <svtools/helpopt.hxx> +#include <vcl/svapp.hxx> +#include <vcl/help.hxx> + +namespace css = ::com::sun::star; + +//........................................................................ +namespace framework +{ + +//----------------------------------------------- +DEFINE_XINTERFACE_4(HelpAgentDispatcher , + OWeakObject , + DIRECT_INTERFACE (css::lang::XTypeProvider ), + DIRECT_INTERFACE (css::frame::XDispatch ), + DIRECT_INTERFACE (css::awt::XWindowListener), + DIRECT_INTERFACE (css::lang::XEventListener)) + +//----------------------------------------------- +DEFINE_XTYPEPROVIDER_2(HelpAgentDispatcher , + css::lang::XTypeProvider, + css::frame::XDispatch ) + +//-------------------------------------------------------------------- +HelpAgentDispatcher::HelpAgentDispatcher( const css::uno::Reference< css::frame::XFrame >& xParentFrame) + : ThreadHelpBase (&Application::GetSolarMutex()) + , m_sCurrentURL ( ) + , m_xContainerWindow( ) + , m_xAgentWindow ( ) + , m_aTimer ( ) + , m_xSelfHold ( ) +{ + // It's required that this class has to be contructed with a valid frame. + // And "valid" means: the frame must already bound to a valid container window. + m_xContainerWindow = xParentFrame->getContainerWindow(); +} + +//-------------------------------------------------------------------- +HelpAgentDispatcher::~HelpAgentDispatcher() +{ + implts_stopTimer(); + implts_ignoreCurrentURL(); + + // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. + css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); + if (xAgentWindow.is()) + xAgentWindow->dispose(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::dispatch(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >&) + throw(css::uno::RuntimeException) +{ + // silently drop the request if the new URL was marked to be ignored next time. + sal_Int32 nAllowedToIgnore = SvtHelpOptions().getAgentIgnoreURLCounter(aURL.Complete); + if (nAllowedToIgnore < 1) + return; + + // stop the expiration timer for the old URL + // The timer will add the old URL to the list of ignorable URLs. + // So m_sCurrentURL must be set AFTER the timer was stopped !!! + implts_stopTimer(); + + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_sCurrentURL = aURL.Complete; + aWriteLock.unlock(); + // <- SAFE + + // start the expiration timer for the new URL + implts_startTimer(); + + // make sure the agent window is shown + implts_showAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL&) + throw(css::uno::RuntimeException) +{ + // no status available +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL&) + throw(css::uno::RuntimeException) +{ + // no status available +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowResized(const css::awt::WindowEvent&) + throw(css::uno::RuntimeException) +{ + implts_positionAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowMoved(const css::awt::WindowEvent&) + throw(css::uno::RuntimeException) +{ + implts_positionAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowShown(const css::lang::EventObject&) + throw(css::uno::RuntimeException) +{ + implts_showAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::windowHidden(const css::lang::EventObject&) + throw(css::uno::RuntimeException) +{ + implts_hideAgentWindow(); +} + +//-------------------------------------------------------------------- +void SAL_CALL HelpAgentDispatcher::disposing(const css::lang::EventObject& aEvent) + throw(css::uno::RuntimeException) +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + // Already disposed ?! + if (! m_xContainerWindow.is()) + return; + // Wrong broadcaster ?! + if (aEvent.Source != m_xContainerWindow) + return; + + css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + m_xSelfHold.clear(); + + aWriteLock.unlock(); + // <- SAFE + + implts_stopTimer(); + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); + + // SAFE -> + aWriteLock.lock(); + m_xContainerWindow.clear(); + css::uno::Reference< css::lang::XComponent > xAgentWindow(m_xAgentWindow, css::uno::UNO_QUERY); + m_xAgentWindow.clear(); + aWriteLock.unlock(); + // <- SAFE + + // Needed ... because it was create as "new VCLWindow()" ! Such windows must be disposed explicitly. + if (xAgentWindow.is()) + xAgentWindow->dispose(); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::helpRequested() +{ + implts_stopTimer(); + implts_hideAgentWindow(); + implts_acceptCurrentURL(); +} + +//----------------------------------------------- +void HelpAgentDispatcher::closeAgent() +{ + implts_stopTimer(); + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_acceptCurrentURL() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + ::rtl::OUString sAcceptedURL = m_sCurrentURL; + m_sCurrentURL = ::rtl::OUString(); + + aWriteLock.unlock(); + // <- SAFE + + // We must make sure that this URL isnt marked as ignored by the user. + // Otherwhise the user wont see the corresponding help content in the future. + SvtHelpOptions().resetAgentIgnoreURLCounter(sAcceptedURL); + + // show the right help content + // SOLAR SAFE -> + { + SolarMutexGuard aSolarLock; + Help* pHelp = Application::GetHelp(); + if (pHelp) + pHelp->Start(sAcceptedURL, NULL); + } + // <- SOLAR SAFE +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_ignoreCurrentURL() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + + ::rtl::OUString sIgnoredURL = m_sCurrentURL; + m_sCurrentURL = ::rtl::OUString(); + + aWriteLock.unlock(); + // <- SAFE + + if (sIgnoredURL.getLength()) + SvtHelpOptions().decAgentIgnoreURLCounter(sIgnoredURL); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_stopTimer() +{ + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_xSelfHold.clear(); + aWriteLock.unlock(); + // <- SAFE + + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + SolarMutexGuard aSolarLock; + if (! m_aTimer.IsActive()) + return; + m_aTimer.Stop(); + } + // <- SOLAR SAFE +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_startTimer() +{ + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + SolarMutexGuard aSolarLock; + if (m_aTimer.IsActive()) + return; + } + // <- SOLAR SAFE + + // SAFE -> + // Timer uses pointer to this help agent dispatcher ... + // But normaly we are ref counted. So we must make sure that this + // dispatcher isnt killed during the timer runs .-) + WriteGuard aWriteLock(m_aLock); + m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + aWriteLock.unlock(); + // <- SAFE + + sal_Int32 nTime = SvtHelpOptions().GetHelpAgentTimeoutPeriod(); + + // SOLAR SAFE -> + // Timer access needs no "own lock" ! It lives if we live ... + // But it requires locking of the solar mutex ... because it's a vcl based timer. + { + SolarMutexGuard aSolarLock; + m_aTimer.SetTimeout(nTime*1000); // sec => ms ! + m_aTimer.Start(); + } +} + +//----------------------------------------------- +IMPL_LINK(HelpAgentDispatcher, implts_timerExpired, void*,) +{ + // This method is called by using a pointer to us. + // But we must be aware that we can be destroyed hardly + // if our uno reference will be gone! + // => Hold this object alive till this method finish its work. + // SAFE -> + WriteGuard aWriteLock(m_aLock); + css::uno::Reference< css::uno::XInterface > xSelfHoldUntilMethodEnds(static_cast< css::frame::XDispatch* >(this), css::uno::UNO_QUERY_THROW); + m_xSelfHold.clear(); + aWriteLock.unlock(); + // <- SAFE + + implts_hideAgentWindow(); + implts_ignoreCurrentURL(); + + return 0; +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_showAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::awt::XWindow2 > xContainerWindow(m_xContainerWindow, css::uno::UNO_QUERY_THROW); + aReadLock.unlock(); + // <- SAFE + + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + + if ( + (xContainerWindow.is() ) && + (xAgentWindow.is() ) && + (xContainerWindow->isVisible()) + ) + { + // make sure that agent window resists at the right place .-) + implts_positionAgentWindow(); + xAgentWindow->setVisible(sal_True); + } +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_hideAgentWindow() +{ + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + if (xAgentWindow.is()) + xAgentWindow->setVisible(sal_False); +} + +//-------------------------------------------------------------------- +void HelpAgentDispatcher::implts_positionAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; + aReadLock.unlock(); + // <- SAFE + + css::uno::Reference< css::awt::XWindow > xAgentWindow = implts_ensureAgentWindow(); + if ( + (! xContainerWindow.is()) || + (! xAgentWindow.is() ) + ) + return; + + ::svt::HelpAgentWindow* pAgentWindow = (::svt::HelpAgentWindow*)VCLUnoHelper::GetWindow(xAgentWindow); + const css::awt::Rectangle aContainerSize = xContainerWindow->getPosSize(); + const Size aAgentSize = pAgentWindow->getPreferredSizePixel(); + + sal_Int32 nW = aAgentSize.Width() ; + sal_Int32 nH = aAgentSize.Height(); + + if (nW < 1) + nW = 100; + if (nH < 1) + nH = 100; + + sal_Int32 nX = aContainerSize.Width - nW; + sal_Int32 nY = aContainerSize.Height - nH; + + // TODO: use a surrogate if the container window is too small to contain the full-sized agent window + xAgentWindow->setPosSize(nX, nY, nW, nH, css::awt::PosSize::POSSIZE); +} + +//-------------------------------------------------------------------- +css::uno::Reference< css::awt::XWindow > HelpAgentDispatcher::implts_ensureAgentWindow() +{ + // SAFE -> + ReadGuard aReadLock(m_aLock); + if (m_xAgentWindow.is()) + return m_xAgentWindow; + css::uno::Reference< css::awt::XWindow > xContainerWindow = m_xContainerWindow; + aReadLock.unlock(); + // <- SAFE + + if (!xContainerWindow.is()) + return css::uno::Reference< css::awt::XWindow >(); + + ::svt::HelpAgentWindow* pAgentWindow = 0; + // SOLAR SAFE -> + { + SolarMutexGuard aSolarLock; + // create the agent window + Window* pContainerWindow = VCLUnoHelper::GetWindow(xContainerWindow); + pAgentWindow = new ::svt::HelpAgentWindow(pContainerWindow); + pAgentWindow->setCallback(this); + } + // <- SOLAR SAFE + + // SAFE -> + WriteGuard aWriteLock(m_aLock); + m_xAgentWindow = VCLUnoHelper::GetInterface(pAgentWindow); + css::uno::Reference< css::awt::XWindow > xAgentWindow = m_xAgentWindow; + aWriteLock.unlock(); + // <- SAFE + + // add as window listener to the container window so we can maintain the property position of the agent window + xContainerWindow->addWindowListener(this); + + // SOLAR SAFE -> + { + SolarMutexGuard aSolarLock; + // establish callback for our internal used timer. + // Note: Its only active, if the timer will be started ... + m_aTimer.SetTimeoutHdl(LINK(this, HelpAgentDispatcher, implts_timerExpired)); + } + // <- SOLAR SAFE + + return xAgentWindow; +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/interaction.cxx b/framework/source/dispatch/interaction.cxx new file mode 100644 index 000000000000..5c37ce12d317 --- /dev/null +++ b/framework/source/dispatch/interaction.cxx @@ -0,0 +1,212 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/interaction.hxx> +#include <general.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//--------------------------------------------------------------------------------------------------------- +// initialize continuation with right start values +//--------------------------------------------------------------------------------------------------------- +ContinuationFilterSelect::ContinuationFilterSelect() + : m_sFilter( ::rtl::OUString() ) +{ +} + +//--------------------------------------------------------------------------------------------------------- +// handler should use it after selection to set user specified filter for transport +//--------------------------------------------------------------------------------------------------------- +void SAL_CALL ContinuationFilterSelect::setFilter( const ::rtl::OUString& sFilter ) throw( css::uno::RuntimeException ) +{ + m_sFilter = sFilter; +} + +//--------------------------------------------------------------------------------------------------------- +// read access to transported filter +//--------------------------------------------------------------------------------------------------------- +::rtl::OUString SAL_CALL ContinuationFilterSelect::getFilter() throw( css::uno::RuntimeException ) +{ + return m_sFilter; +} + +//--------------------------------------------------------------------------------------------------------- +// initialize instance with all neccessary informations +// We use it without any further checks on our member then ...! +//--------------------------------------------------------------------------------------------------------- +RequestFilterSelect::RequestFilterSelect( const ::rtl::OUString& sURL ) +{ + ::rtl::OUString temp; + css::uno::Reference< css::uno::XInterface > temp2; + css::document::NoSuchFilterRequest aFilterRequest( temp , + temp2 , + sURL ); + m_aRequest <<= aFilterRequest; + + m_pAbort = new ContinuationAbort ; + m_pFilter = new ContinuationFilterSelect; + + m_lContinuations.realloc( 2 ); + m_lContinuations[0] = css::uno::Reference< css::task::XInteractionContinuation >( m_pAbort ); + m_lContinuations[1] = css::uno::Reference< css::task::XInteractionContinuation >( m_pFilter ); +} + +//--------------------------------------------------------------------------------------------------------- +// return abort state of interaction +// If it is true, return value of method "getFilter()" will be unspecified then! +//--------------------------------------------------------------------------------------------------------- +sal_Bool RequestFilterSelect::isAbort() const +{ + return m_pAbort->isSelected(); +} + +//--------------------------------------------------------------------------------------------------------- +// return user selected filter +// Return value valid for non aborted interaction only. Please check "isAbort()" before you call these ony! +//--------------------------------------------------------------------------------------------------------- +::rtl::OUString RequestFilterSelect::getFilter() const +{ + return m_pFilter->getFilter(); +} + +//--------------------------------------------------------------------------------------------------------- +// handler call it to get type of request +// Is hard coded to "please select filter" here. see ctor for further informations. +//--------------------------------------------------------------------------------------------------------- +css::uno::Any SAL_CALL RequestFilterSelect::getRequest() throw( css::uno::RuntimeException ) +{ + return m_aRequest; +} + +//--------------------------------------------------------------------------------------------------------- +// handler call it to get possible continuations +// We support "abort/select_filter" only here. +// After interaction we support read access on these continuations on our c++ interface to +// return user decision. +//--------------------------------------------------------------------------------------------------------- +css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > SAL_CALL RequestFilterSelect::getContinuations() throw( css::uno::RuntimeException ) +{ + return m_lContinuations; +} + +//--------------------------------------------------------------------------------------------------------- +// initialize instance with all neccessary informations +// We use it without any further checks on our member then ...! +//--------------------------------------------------------------------------------------------------------- +RequestAmbigousFilter::RequestAmbigousFilter( const ::rtl::OUString& sURL , + const ::rtl::OUString& sSelectedFilter , + const ::rtl::OUString& sDetectedFilter ) +{ + ::rtl::OUString temp; + css::uno::Reference< css::uno::XInterface > temp2; + css::document::AmbigousFilterRequest aFilterRequest( temp , + temp2 , + sURL , + sSelectedFilter , + sDetectedFilter ); + m_aRequest <<= aFilterRequest; + + m_pAbort = new ContinuationAbort ; + m_pFilter = new ContinuationFilterSelect; + + m_lContinuations.realloc( 2 ); + m_lContinuations[0] = css::uno::Reference< css::task::XInteractionContinuation >( m_pAbort ); + m_lContinuations[1] = css::uno::Reference< css::task::XInteractionContinuation >( m_pFilter ); +} + +//--------------------------------------------------------------------------------------------------------- +// return abort state of interaction +// If it is true, return value of method "getFilter()" will be unspecified then! +//--------------------------------------------------------------------------------------------------------- +sal_Bool RequestAmbigousFilter::isAbort() const +{ + return m_pAbort->isSelected(); +} + +//--------------------------------------------------------------------------------------------------------- +// return user selected filter +// Return value valid for non aborted interaction only. Please check "isAbort()" before you call these ony! +//--------------------------------------------------------------------------------------------------------- +::rtl::OUString RequestAmbigousFilter::getFilter() const +{ + return m_pFilter->getFilter(); +} + +//--------------------------------------------------------------------------------------------------------- +// handler call it to get type of request +// Is hard coded to "please select filter" here. see ctor for further informations. +//--------------------------------------------------------------------------------------------------------- +css::uno::Any SAL_CALL RequestAmbigousFilter::getRequest() throw( css::uno::RuntimeException ) +{ + return m_aRequest; +} + +//--------------------------------------------------------------------------------------------------------- +// handler call it to get possible continuations +// We support "abort/select_filter" only here. +// After interaction we support read access on these continuations on our c++ interface to +// return user decision. +//--------------------------------------------------------------------------------------------------------- +css::uno::Sequence< css::uno::Reference< css::task::XInteractionContinuation > > SAL_CALL RequestAmbigousFilter::getContinuations() throw( css::uno::RuntimeException ) +{ + return m_lContinuations; +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/interceptionhelper.cxx b/framework/source/dispatch/interceptionhelper.cxx new file mode 100644 index 000000000000..8dc54239ad0e --- /dev/null +++ b/framework/source/dispatch/interceptionhelper.cxx @@ -0,0 +1,343 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_______________________________________________ +// my own includes + +#include <dispatch/interceptionhelper.hxx> + +//_______________________________________________ +// interface includes +#include <com/sun/star/frame/XInterceptorInfo.hpp> + +//_______________________________________________ +// includes of other projects +#include <vcl/svapp.hxx> + +//_______________________________________________ +// namespace + +namespace framework{ + +//_______________________________________________ +// non exported const + +sal_Bool InterceptionHelper::m_bPreferrFirstInterceptor = sal_True; + +//_______________________________________________ +// non exported definitions + +//_______________________________________________ +// declarations + +/*----------------------------------------------------------------------------- + 31.03.2003 09:02 +-----------------------------------------------------------------------------*/ +DEFINE_XINTERFACE_3(InterceptionHelper , + OWeakObject , + DIRECT_INTERFACE(css::frame::XDispatchProvider ), + DIRECT_INTERFACE(css::frame::XDispatchProviderInterception), + DIRECT_INTERFACE(css::lang::XEventListener )) + +/*----------------------------------------------------------------------------- + 31.03.2003 09:02 +-----------------------------------------------------------------------------*/ +InterceptionHelper::InterceptionHelper(const css::uno::Reference< css::frame::XFrame >& xOwner, + const css::uno::Reference< css::frame::XDispatchProvider >& xSlave) + // Init baseclasses first + : ThreadHelpBase(&Application::GetSolarMutex()) + , OWeakObject ( ) + // Init member + , m_xOwnerWeak (xOwner ) + , m_xSlave (xSlave ) +{ +} + +/*----------------------------------------------------------------------------- + 31.03.2003 09:02 +-----------------------------------------------------------------------------*/ +InterceptionHelper::~InterceptionHelper() +{ +} + +/*----------------------------------------------------------------------------- + 31.03.2003 09:09 +-----------------------------------------------------------------------------*/ +css::uno::Reference< css::frame::XDispatch > SAL_CALL InterceptionHelper::queryDispatch(const css::util::URL& aURL , + const ::rtl::OUString& sTargetFrameName, + sal_Int32 nSearchFlags ) + throw(css::uno::RuntimeException) +{ + // SAFE { + ReadGuard aReadLock(m_aLock); + + // a) first search an interceptor, which match to this URL by it's URL pattern registration + // Note: if it return NULL - it does not mean an empty interceptor list automaticly! + css::uno::Reference< css::frame::XDispatchProvider > xInterceptor; + InterceptorList::const_iterator pIt = m_lInterceptionRegs.findByPattern(aURL.Complete); + if (pIt != m_lInterceptionRegs.end()) + xInterceptor = pIt->xInterceptor; + + // b) No match by registration - but a valid interceptor list. + // Use first interceptor everytimes. + // Note: it doesn't matter, which direction this helper implementation use to ask interceptor objects. + // Using of member m_aInterceptorList will starts at the beginning everytimes. + // It depends from the filling operation, in which direction it works realy! + if (!xInterceptor.is() && m_lInterceptionRegs.size()>0) + { + pIt = m_lInterceptionRegs.begin(); + xInterceptor = pIt->xInterceptor; + } + + // c) No registered interceptor => use our direct slave. + // This helper exist by design and must be valid everytimes ... + // But to be more feature proof - we should check that .-) + if (!xInterceptor.is() && m_xSlave.is()) + xInterceptor = m_xSlave; + + aReadLock.unlock(); + // } SAFE + + css::uno::Reference< css::frame::XDispatch > xReturn; + if (xInterceptor.is()) + xReturn = xInterceptor->queryDispatch(aURL, sTargetFrameName, nSearchFlags); + return xReturn; +} + +/*----------------------------------------------------------------------------- + 31.03.2003 07:58 +-----------------------------------------------------------------------------*/ +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL InterceptionHelper::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) + throw(css::uno::RuntimeException) +{ + sal_Int32 c = lDescriptor.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatches (c); + css::uno::Reference< css::frame::XDispatch >* pDispatches = lDispatches.getArray(); + const css::frame::DispatchDescriptor* pDescriptor = lDescriptor.getConstArray(); + + for (sal_Int32 i=0; i<c; ++i) + pDispatches[i] = queryDispatch(pDescriptor[i].FeatureURL, pDescriptor[i].FrameName, pDescriptor[i].SearchFlags); + + return lDispatches; +} + +/*----------------------------------------------------------------------------- + 31.03.2003 10:20 +-----------------------------------------------------------------------------*/ +void SAL_CALL InterceptionHelper::registerDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) + throw(css::uno::RuntimeException) +{ + // reject wrong calling of this interface method + css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + if (!xInterceptor.is()) + throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis); + + // Fill a new info structure for new interceptor. + // Save his reference and try to get an additional URL/pattern list from him. + // If no list exist register these interceptor for all dispatch events with "*"! + InterceptorInfo aInfo; + + aInfo.xInterceptor = css::uno::Reference< css::frame::XDispatchProvider >(xInterceptor, css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XInterceptorInfo > xInfo(xInterceptor, css::uno::UNO_QUERY); + if (xInfo.is()) + aInfo.lURLPattern = xInfo->getInterceptedURLs(); + else + { + aInfo.lURLPattern.realloc(1); + aInfo.lURLPattern[0] = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("*")); + } + + // SAFE { + WriteGuard aWriteLock(m_aLock); + + // a) no interceptor at all - set this instance as master for given interceptor + // and set our slave as it's slave - and put this interceptor to the list. + // It's place there doesn matter. Because this list is currently empty. + if (m_lInterceptionRegs.empty()) + { + xInterceptor->setMasterDispatchProvider(xThis ); + xInterceptor->setSlaveDispatchProvider (m_xSlave); + m_lInterceptionRegs.push_back(aInfo); + } + + // b) OK - there is at least one interceptor already registered. + // It's slave and it's master must be valid references ... + // because we created it. But we have to look for the static bool which + // regulate direction of using of interceptor objects! + + // b1) If "m_bPreferrFirstInterceptor" is set to true, we have to + // insert it behind any other existing interceptor - means at the end of our list. + else if (m_bPreferrFirstInterceptor) + { + css::uno::Reference< css::frame::XDispatchProvider > xMasterD = m_lInterceptionRegs.rbegin()->xInterceptor; + css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD, css::uno::UNO_QUERY); + + xInterceptor->setMasterDispatchProvider(xMasterD ); + xInterceptor->setSlaveDispatchProvider (m_xSlave ); + xMasterI->setSlaveDispatchProvider (aInfo.xInterceptor); + + m_lInterceptionRegs.push_back(aInfo); + } + + // b2) If "m_bPreferrFirstInterceptor" is set to false, we have to + // insert it before any other existing interceptor - means at the beginning of our list. + else + { + css::uno::Reference< css::frame::XDispatchProvider > xSlaveD = m_lInterceptionRegs.begin()->xInterceptor; + css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); + + xInterceptor->setMasterDispatchProvider(xThis ); + xInterceptor->setSlaveDispatchProvider (xSlaveD ); + xSlaveI->setMasterDispatchProvider (aInfo.xInterceptor); + + m_lInterceptionRegs.push_front(aInfo); + } + + css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); + + aWriteLock.unlock(); + // } SAFE + + // Don't forget to send a frame action event "context changed". + // Any cached dispatch objects must be validated now! + if (xOwner.is()) + xOwner->contextChanged(); +} + +/*----------------------------------------------------------------------------- + 31.03.2003 10:27 +-----------------------------------------------------------------------------*/ +void SAL_CALL InterceptionHelper::releaseDispatchProviderInterceptor(const css::uno::Reference< css::frame::XDispatchProviderInterceptor >& xInterceptor) + throw(css::uno::RuntimeException) +{ + // reject wrong calling of this interface method + css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + if (!xInterceptor.is()) + throw css::uno::RuntimeException(DECLARE_ASCII("NULL references not allowed as in parameter"), xThis); + + // SAFE { + WriteGuard aWriteLock(m_aLock); + + // search this interceptor ... + // If it could be located inside cache - + // use it's slave/master relations to update the interception list; + // set empty references for it as new master and slave; + // and relase it from out cache. + InterceptorList::iterator pIt = m_lInterceptionRegs.findByReference(xInterceptor); + if (pIt != m_lInterceptionRegs.end()) + { + css::uno::Reference< css::frame::XDispatchProvider > xSlaveD (xInterceptor->getSlaveDispatchProvider() , css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchProvider > xMasterD (xInterceptor->getMasterDispatchProvider(), css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchProviderInterceptor > xSlaveI (xSlaveD , css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XDispatchProviderInterceptor > xMasterI (xMasterD , css::uno::UNO_QUERY); + + if (xMasterI.is()) + xMasterI->setSlaveDispatchProvider(xSlaveD); + + if (xSlaveI.is()) + xSlaveI->setMasterDispatchProvider(xMasterD); + + xInterceptor->setSlaveDispatchProvider (css::uno::Reference< css::frame::XDispatchProvider >()); + xInterceptor->setMasterDispatchProvider(css::uno::Reference< css::frame::XDispatchProvider >()); + + m_lInterceptionRegs.erase(pIt); + } + + css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); + + aWriteLock.unlock(); + // } SAFE + + // Don't forget to send a frame action event "context changed". + // Any cached dispatch objects must be validated now! + if (xOwner.is()) + xOwner->contextChanged(); +} + +/*----------------------------------------------------------------------------- + 31.03.2003 10:31 +-----------------------------------------------------------------------------*/ +#define FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN +void SAL_CALL InterceptionHelper::disposing(const css::lang::EventObject& aEvent) + throw(css::uno::RuntimeException) +{ + #ifdef FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN + // SAFE -> + ReadGuard aReadLock(m_aLock); + + // check calli ... we accept such disposing call's only from our onwer frame. + css::uno::Reference< css::frame::XFrame > xOwner(m_xOwnerWeak.get(), css::uno::UNO_QUERY); + if (aEvent.Source != xOwner) + return; + + // Because every interceptor hold at least one reference to us ... and we destruct this list + // of interception objects ... we should hold ourself alive .-) + css::uno::Reference< css::frame::XDispatchProvider > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY_THROW); + + // We need a full copy of all currently registered interceptor objects. + // Otherwhise we cant iterate over this vector without the risk, that our iterator will be invalid. + // Because this vetor will be influenced by every deregistered interceptor. + InterceptionHelper::InterceptorList aCopy = m_lInterceptionRegs; + + aReadLock.unlock(); + // <- SAFE + + InterceptionHelper::InterceptorList::iterator pIt; + for ( pIt = aCopy.begin(); + pIt != aCopy.end() ; + ++pIt ) + { + InterceptionHelper::InterceptorInfo& rInfo = *pIt; + if (rInfo.xInterceptor.is()) + { + css::uno::Reference< css::frame::XDispatchProviderInterceptor > xInterceptor(rInfo.xInterceptor, css::uno::UNO_QUERY_THROW); + releaseDispatchProviderInterceptor(xInterceptor); + rInfo.xInterceptor.clear(); + } + } + + aCopy.clear(); + + #if OSL_DEBUG_LEVEL > 0 + // SAFE -> + aReadLock.lock(); + if (!m_lInterceptionRegs.empty() ) + OSL_ENSURE(sal_False, "There are some pending interceptor objects, which seams to be registered during (!) the destruction of a frame."); + aReadLock.unlock(); + // <- SAFE + #endif // ODL_DEBUG_LEVEL>0 + + #endif // FORCE_DESTRUCTION_OF_INTERCEPTION_CHAIN +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/loaddispatcher.cxx b/framework/source/dispatch/loaddispatcher.cxx new file mode 100644 index 000000000000..31accd649aa7 --- /dev/null +++ b/framework/source/dispatch/loaddispatcher.cxx @@ -0,0 +1,201 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_______________________________________________ +// my own includes +#include <dispatch/loaddispatcher.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> + +//_______________________________________________ +// interface includes +#include <com/sun/star/frame/DispatchResultState.hpp> + +//_______________________________________________ +// includes of other projects + +//_______________________________________________ +// namespace + +namespace framework{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// declarations + +/*----------------------------------------------- + 20.08.2003 09:52 +-----------------------------------------------*/ +LoadDispatcher::LoadDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xOwnerFrame , + const ::rtl::OUString sTargetName , + sal_Int32 nSearchFlags) + : ThreadHelpBase( ) + , m_xSMGR (xSMGR ) + , m_xOwnerFrame (xOwnerFrame ) + , m_sTarget (sTargetName ) + , m_nSearchFlags(nSearchFlags) + , m_aLoader (xSMGR ) +{ +} + +/*----------------------------------------------- + 20.08.2003 09:12 +-----------------------------------------------*/ +LoadDispatcher::~LoadDispatcher() +{ + m_xSMGR.clear(); +} + +/*----------------------------------------------- + 20.08.2003 09:58 +-----------------------------------------------*/ +void SAL_CALL LoadDispatcher::dispatchWithNotification(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) + throw(css::uno::RuntimeException) +{ + impl_dispatch( aURL, lArguments, xListener ); +} + +/*----------------------------------------------- + 20.08.2003 09:16 +-----------------------------------------------*/ +void SAL_CALL LoadDispatcher::dispatch(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments) + throw(css::uno::RuntimeException) +{ + impl_dispatch( aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >() ); +} + +/*----------------------------------------------- + 14.04.2008 +-----------------------------------------------*/ +css::uno::Any SAL_CALL LoadDispatcher::dispatchWithReturnValue( const css::util::URL& rURL, + const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) + throw( css::uno::RuntimeException ) +{ + return impl_dispatch( rURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >()); +} + +/*----------------------------------------------- + 20.08.2003 10:48 +-----------------------------------------------*/ +void SAL_CALL LoadDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +/*----------------------------------------------- + 20.08.2003 10:49 +-----------------------------------------------*/ +void SAL_CALL LoadDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +/*----------------------------------------------- + 20.08.2003 09:58 +-----------------------------------------------*/ +css::uno::Any LoadDispatcher::impl_dispatch( const css::util::URL& rURL, + const css::uno::Sequence< css::beans::PropertyValue >& lArguments, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) +{ + // Attention: May be nobody outside hold such temp. dispatch object alive (because + // the container in which we resists isnt implemented threadsafe but updated by a timer + // and clear our reference ...) we should hold us self alive! + css::uno::Reference< css::uno::XInterface > xThis(static_cast< css::frame::XNotifyingDispatch* >(this), css::uno::UNO_QUERY); + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + + // We are the only client of this load env object ... but + // may a dispatch request before is still in progress (?!). + // Then we should wait a little bit and block this new request. + // In case we run into the timeout, we should reject this new request + // and return "FAILED" as result. Otherwhise we can start this new operation. + if (!m_aLoader.waitWhileLoading(2000)) // => 2 sec. + { + if (xListener.is()) + xListener->dispatchFinished( + css::frame::DispatchResultEvent(xThis, css::frame::DispatchResultState::DONTKNOW, css::uno::Any())); // DONTKNOW? ... not realy started ... not realy failed :-) + } + + css::uno::Reference< css::frame::XFrame > xBaseFrame(m_xOwnerFrame.get(), css::uno::UNO_QUERY); + if (!xBaseFrame.is()) + { + if (xListener.is()) + xListener->dispatchFinished( + css::frame::DispatchResultEvent(xThis, css::frame::DispatchResultState::FAILURE, css::uno::Any())); + } + + // OK ... now the internal loader seems to be useable for new requests + // and our owner frame seems to be valid for such operations. + // Initialize it with all new but needed properties and start the loading. + css::uno::Reference< css::lang::XComponent > xComponent; + try + { + m_aLoader.initializeLoading( rURL.Complete, lArguments, xBaseFrame, m_sTarget, m_nSearchFlags, (LoadEnv::EFeature)(LoadEnv::E_ALLOW_CONTENTHANDLER | LoadEnv::E_WORK_WITH_UI)); + m_aLoader.startLoading(); + m_aLoader.waitWhileLoading(); // wait for ever! + xComponent = m_aLoader.getTargetComponent(); + + // TODO thinking about asynchronous operations and listener support + } + catch(const LoadEnvException&) + { xComponent.clear(); } + + if (xListener.is()) + { + if (xComponent.is()) + xListener->dispatchFinished( + css::frame::DispatchResultEvent(xThis, css::frame::DispatchResultState::SUCCESS, css::uno::Any())); + else + xListener->dispatchFinished( + css::frame::DispatchResultEvent(xThis, css::frame::DispatchResultState::FAILURE, css::uno::Any())); + } + + // return the model - like loadComponentFromURL() + css::uno::Any aRet; + if ( xComponent.is () ) + aRet = css::uno::makeAny( xComponent ); + + aReadLock.unlock(); + // <- SAFE ---------------------------------- + return aRet; +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/mailtodispatcher.cxx b/framework/source/dispatch/mailtodispatcher.cxx new file mode 100644 index 000000000000..3c505540ae33 --- /dev/null +++ b/framework/source/dispatch/mailtodispatcher.cxx @@ -0,0 +1,333 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/mailtodispatcher.hxx> +#include <threadhelp/readguard.hxx> +#include <general.h> +#include <services.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/system/XSystemShellExecute.hpp> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <com/sun/star/frame/DispatchResultState.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <vcl/svapp.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +#define PROTOCOL_VALUE "mailto:" +#define PROTOCOL_LENGTH 7 + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// XInterface, XTypeProvider, XServiceInfo + +DEFINE_XINTERFACE_5(MailToDispatcher , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::lang::XServiceInfo ), + DIRECT_INTERFACE(css::frame::XDispatchProvider ), + DIRECT_INTERFACE(css::frame::XNotifyingDispatch), + DIRECT_INTERFACE(css::frame::XDispatch )) + +DEFINE_XTYPEPROVIDER_5(MailToDispatcher , + css::lang::XTypeProvider , + css::lang::XServiceInfo , + css::frame::XDispatchProvider , + css::frame::XNotifyingDispatch, + css::frame::XDispatch ) + +DEFINE_XSERVICEINFO_MULTISERVICE(MailToDispatcher , + ::cppu::OWeakObject , + SERVICENAME_PROTOCOLHANDLER , + IMPLEMENTATIONNAME_MAILTODISPATCHER) + +DEFINE_INIT_SERVICE(MailToDispatcher, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + } + ) + +//_________________________________________________________________________________________________________________ + +/** + @short standard ctor + @descr These initialize a new instance of ths class with needed informations for work. + + @param xFactory + reference to uno servicemanager for creation of new services + + @modified 30.04.2002 14:10, as96863 +*/ +MailToDispatcher::MailToDispatcher( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory ) + // Init baseclasses first + : ThreadHelpBase( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) +{ +} + +//_________________________________________________________________________________________________________________ + +/** + @short standard dtor + @descr - + + @modified 30.04.2002 14:10, as96863 +*/ +MailToDispatcher::~MailToDispatcher() +{ + m_xFactory = NULL; +} + +//_________________________________________________________________________________________________________________ + +/** + @short decide if this dispatch implementation can be used for requested URL or not + @descr A protocol handler is registerd for an URL pattern inside configuration and will + be asked by the generic dispatch mechanism inside framework, if he can handle this + special URL wich match his registration. He can agree by returning of a valid dispatch + instance or disagree by returning <NULL/>. + We don't create new dispatch instances here realy - we return THIS as result to handle it + at the same implementation. + + @modified 02.05.2002 15:25, as96863 +*/ +css::uno::Reference< css::frame::XDispatch > SAL_CALL MailToDispatcher::queryDispatch( const css::util::URL& aURL , + const ::rtl::OUString& /*sTarget*/ , + sal_Int32 /*nFlags*/ ) throw( css::uno::RuntimeException ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0) + xDispatcher = this; + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short do the same like dispatch() but for multiple requests at the same time + @descr - + + @modified 02.05.2002 15:27, as96863 +*/ +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL MailToDispatcher::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException ) +{ + sal_Int32 nCount = lDescriptor.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = this->queryDispatch( + lDescriptor[i].FeatureURL, + lDescriptor[i].FrameName, + lDescriptor[i].SearchFlags); + } + return lDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short dispatch URL with arguments + @descr We use threadsafe internal method to do so. It returns a state value - but we ignore it. + Because we doesn't support status listener notifications here. Status events are not guaranteed - + and we call another service internaly which doesn't return any notifications too. + + @param aURL + mail URL which should be executed + @param lArguments + list of optional arguments for this mail request + + @modified 30.04.2002 14:15, as96863 +*/ +void SAL_CALL MailToDispatcher::dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException ) +{ + // dispatch() is an [oneway] call ... and may our user release his reference to us immediatly. + // So we should hold us self alive till this call ends. + css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + implts_dispatch(aURL,lArguments); + // No notification for status listener! +} + +//_________________________________________________________________________________________________________________ + +/** + @short dispatch with guaranteed notifications about success + @descr We use threadsafe internal method to do so. Return state of this function will be used + for notification if an optional listener is given. + + @param aURL + mail URL which should be executed + @param lArguments + list of optional arguments for this mail request + @param xListener + reference to a valid listener for state events + + @modified 30.04.2002 14:49, as96863 +*/ +void SAL_CALL MailToDispatcher::dispatchWithNotification( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException ) +{ + // This class was designed to die by reference. And if user release his reference to us immediatly after calling this method + // we can run into some problems. So we hold us self alive till this method ends. + // Another reason: We can use this reference as source of sending event at the end too. + css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + + sal_Bool bState = implts_dispatch(aURL,lArguments); + if (xListener.is()) + { + css::frame::DispatchResultEvent aEvent; + if (bState) + aEvent.State = css::frame::DispatchResultState::SUCCESS; + else + aEvent.State = css::frame::DispatchResultState::FAILURE; + aEvent.Source = xThis; + + xListener->dispatchFinished( aEvent ); + } +} + +//_________________________________________________________________________________________________________________ + +/** + @short threadsafe helper for dispatch calls + @descr We support two interfaces for the same process - dispatch URLs. That the reason for this internal + function. It implements the real dispatch operation and returns a state value which inform caller + about success. He can notify listener then by using this return value. + + @param aURL + mail URL which should be executed + @param lArguments + list of optional arguments for this mail request + + @return <TRUE/> if dispatch could be started successfully + Note: Our internal used shell executor doesn't return any state value - so we must + belive that call was successfully. + <FALSE/> if neccessary ressource couldn't be created or an exception was thrown. + + @modified 30.04.2002 14:49, as96863 +*/ +sal_Bool MailToDispatcher::implts_dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/ ) throw( css::uno::RuntimeException ) +{ + sal_Bool bSuccess = sal_False; + + css::uno::Reference< css::lang::XMultiServiceFactory > xFactory; + /* SAFE */{ + ReadGuard aReadLock( m_aLock ); + xFactory = m_xFactory; + /* SAFE */} + + css::uno::Reference< css::system::XSystemShellExecute > xSystemShellExecute( xFactory->createInstance(SERVICENAME_SYSTEMSHELLEXECUTE), css::uno::UNO_QUERY ); + if (xSystemShellExecute.is()) + { + try + { + // start mail client + // Because there is no notofocation about success - we use case of + // no detected exception as SUCCESS - FAILED otherwhise. + xSystemShellExecute->execute( aURL.Complete, ::rtl::OUString(), css::system::SystemShellExecuteFlags::DEFAULTS ); + bSuccess = sal_True; + } + catch (css::lang::IllegalArgumentException&) + { + } + catch (css::system::SystemShellExecuteException&) + { + } + } + + return bSuccess; +} + +//_________________________________________________________________________________________________________________ + +/** + @short add/remove listener for state events + @descr Because we use an external process to forward such mail URLs, and this process doesn't + return any notifications about success or failed state - we doesn't support such status + listener. We have no status to send. + + @param xListener + reference to a valid listener for state events + @param aURL + URL about listener will be informed, if something occurred + + @modified 30.04.2002 14:49, as96863 +*/ +void SAL_CALL MailToDispatcher::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ , + const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL MailToDispatcher::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ , + const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/makefile.mk b/framework/source/dispatch/makefile.mk new file mode 100644 index 000000000000..b969d71ea9fc --- /dev/null +++ b/framework/source/dispatch/makefile.mk @@ -0,0 +1,63 @@ +#************************************************************************* +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. +# +# Copyright 2000, 2010 Oracle and/or its affiliates. +# +# OpenOffice.org - a multi-platform office productivity suite +# +# This file is part of OpenOffice.org. +# +# OpenOffice.org is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License version 3 +# only, as published by the Free Software Foundation. +# +# OpenOffice.org is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License version 3 for more details +# (a copy is included in the LICENSE file that accompanied this code). +# +# You should have received a copy of the GNU Lesser General Public License +# version 3 along with OpenOffice.org. If not, see +# <http://www.openoffice.org/license.html> +# for a copy of the LGPLv3 License. +# +#************************************************************************* +PRJ=..$/.. + +PRJNAME= framework +TARGET= fwk_dispatch +USE_DEFFILE= TRUE +ENABLE_EXCEPTIONS= TRUE + +# --- Settings ----------------------------------------------------- + +.INCLUDE : settings.mk + +# --- defines ------------------------------------------------------ + +CDEFS+=-DCOMPMOD_NAMESPACE=framework + +# --- Generate ----------------------------------------------------- + +SLOFILES=\ + $(SLO)$/closedispatcher.obj \ + $(SLO)$/dispatchinformationprovider.obj \ + $(SLO)$/dispatchprovider.obj \ + $(SLO)$/helpagentdispatcher.obj \ + $(SLO)$/interaction.obj \ + $(SLO)$/interceptionhelper.obj \ + $(SLO)$/loaddispatcher.obj \ + $(SLO)$/mailtodispatcher.obj \ + $(SLO)$/menudispatcher.obj \ + $(SLO)$/oxt_handler.obj \ + $(SLO)$/popupmenudispatcher.obj \ + $(SLO)$/servicehandler.obj \ + $(SLO)$/systemexec.obj \ + $(SLO)$/windowcommanddispatch.obj \ + $(SLO)$/startmoduledispatcher.obj + +# --- Targets ------------------------------------------------------ + +.INCLUDE : target.mk diff --git a/framework/source/dispatch/menudispatcher.cxx b/framework/source/dispatch/menudispatcher.cxx new file mode 100644 index 000000000000..248df065e38d --- /dev/null +++ b/framework/source/dispatch/menudispatcher.cxx @@ -0,0 +1,488 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/menudispatcher.hxx> +#include <general.h> +#include <xml/menuconfiguration.hxx> +#include <classes/addonmenu.hxx> +#include <services.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/awt/XToolkit.hpp> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/awt/WindowDescriptor.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumeration.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +#include <vcl/window.hxx> +#include <vcl/syswin.hxx> +#include <vcl/menu.hxx> +#include <vcl/svapp.hxx> +#include <tools/resmgr.hxx> +#include <tools/rcid.h> +#include <osl/mutex.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <rtl/logfile.hxx> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <ucbhelper/content.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +using namespace ::com::sun::star ; +using namespace ::com::sun::star::awt ; +using namespace ::com::sun::star::beans ; +using namespace ::com::sun::star::container ; +using namespace ::com::sun::star::frame ; +using namespace ::com::sun::star::lang ; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::util ; +using namespace ::cppu ; + using ::rtl::OUString; +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +const USHORT SLOTID_MDIWINDOWLIST = 5610; + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//***************************************************************************************************************** +// constructor +//***************************************************************************************************************** +MenuDispatcher::MenuDispatcher( const uno::Reference< XMultiServiceFactory >& xFactory , + const uno::Reference< XFrame >& xOwner ) + // Init baseclasses first + : ThreadHelpBase ( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xOwnerWeak ( xOwner ) + , m_xFactory ( xFactory ) + , m_aListenerContainer ( m_aLock.getShareableOslMutex() ) + , m_bAlreadyDisposed ( sal_False ) + , m_bActivateListener ( sal_False ) + , m_pMenuManager ( NULL ) +{ + // Safe impossible cases + // We need valid informations about ouer ownerfor work. + LOG_ASSERT( impldbg_checkParameter_MenuDispatcher( xFactory, xOwner ), "MenuDispatcher::MenuDispatcher()\nInvalid parameter detected!\n" ) + + m_bActivateListener = sal_True; + xOwner->addFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY )); +} + +//***************************************************************************************************************** +// destructor +//***************************************************************************************************************** +MenuDispatcher::~MenuDispatcher() +{ + // Warn programmer if he forgot to dispose this instance. + // We must release all our references ... + // and a dtor isn't the best place to do that! +} + +//***************************************************************************************************************** +// XInterface, XTypeProvider +//***************************************************************************************************************** +DEFINE_XINTERFACE_4 ( MenuDispatcher , + OWeakObject , + DIRECT_INTERFACE( XTypeProvider ), + DIRECT_INTERFACE( XDispatch ), + DIRECT_INTERFACE( XEventListener ), + DERIVED_INTERFACE( XFrameActionListener, XEventListener ) + ) + +DEFINE_XTYPEPROVIDER_4 ( MenuDispatcher , + XTypeProvider , + XDispatch , + XEventListener , + XFrameActionListener + ) + + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void SAL_CALL MenuDispatcher::dispatch( const URL& /*aURL*/ , + const Sequence< PropertyValue >& /*seqProperties*/ ) throw( RuntimeException ) +{ +} + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void SAL_CALL MenuDispatcher::addStatusListener( const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + // Method not defined for all incoming parameter + LOG_ASSERT( impldbg_checkParameter_addStatusListener( xControl, aURL ), "MenuDispatcher::addStatusListener()\nInvalid parameter detected.\n" ) + // Add listener to container. + m_aListenerContainer.addInterface( aURL.Complete, xControl ); +} + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void SAL_CALL MenuDispatcher::removeStatusListener( const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + // Method not defined for all incoming parameter + LOG_ASSERT( impldbg_checkParameter_removeStatusListener( xControl, aURL ), "MenuDispatcher::removeStatusListener()\nInvalid parameter detected.\n" ) + // Add listener to container. + m_aListenerContainer.removeInterface( aURL.Complete, xControl ); +} + +//***************************************************************************************************************** +// XFrameActionListener +//***************************************************************************************************************** + +void SAL_CALL MenuDispatcher::frameAction( const FrameActionEvent& aEvent ) throw ( RuntimeException ) +{ + ResetableGuard aGuard( m_aLock ); + + if ( m_pMenuManager && aEvent.Action == FrameAction_FRAME_UI_ACTIVATED ) + { + MenuBar* pMenuBar = (MenuBar *)m_pMenuManager->GetMenu(); + uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY ); + aGuard.unlock(); + + if ( xFrame.is() && pMenuBar ) + { + uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow(); + + SolarMutexGuard aSolarGuard; + { + Window* pWindow = VCLUnoHelper::GetWindow( xContainerWindow ); + while ( pWindow && !pWindow->IsSystemWindow() ) + pWindow = pWindow->GetParent(); + + if ( pWindow ) + { + SystemWindow* pSysWindow = (SystemWindow *)pWindow; + pSysWindow->SetMenuBar( pMenuBar ); + } + } + } + } + else if ( m_pMenuManager && aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING ) + { + if ( m_pMenuManager ) + impl_setMenuBar( NULL ); + } +} + +//***************************************************************************************************************** +// XEventListener +//***************************************************************************************************************** +void SAL_CALL MenuDispatcher::disposing( const EventObject& ) throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + LOG_ASSERT( !(m_bAlreadyDisposed==sal_True), "MenuDispatcher::disposing()\nObject already disposed .. don't call it again!\n" ) + + if( m_bAlreadyDisposed == sal_False ) + { + m_bAlreadyDisposed = sal_True; + + if ( m_bActivateListener ) + { + uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY ); + if ( xFrame.is() ) + { + xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY )); + m_bActivateListener = sal_False; + if ( m_pMenuManager ) + { + EventObject aEventObj; + aEventObj.Source = xFrame; + m_pMenuManager->disposing( aEventObj ); + } + } + } + + // Forget our factory. + m_xFactory = uno::Reference< XMultiServiceFactory >(); + + // Remove our menu from system window if it is still there! + if ( m_pMenuManager ) + impl_setMenuBar( NULL ); + } +} + +//***************************************************************************************************************** +// private method +// +// +//***************************************************************************************************************** +void MenuDispatcher::impl_setAccelerators( Menu* pMenu, const Accelerator& aAccel ) +{ + for ( USHORT nPos = 0; nPos < pMenu->GetItemCount(); ++nPos ) + { + USHORT nId = pMenu->GetItemId(nPos); + PopupMenu* pPopup = pMenu->GetPopupMenu(nId); + if ( pPopup ) + impl_setAccelerators( (Menu *)pPopup, aAccel ); + else if ( nId && !pMenu->GetPopupMenu(nId)) + { + KeyCode aCode = aAccel.GetKeyCode( nId ); + if ( aCode.GetCode() ) + pMenu->SetAccelKey( nId, aCode ); + } + } +} + +//***************************************************************************************************************** +// private method +// +// +//***************************************************************************************************************** +sal_Bool MenuDispatcher::impl_setMenuBar( MenuBar* pMenuBar, sal_Bool bMenuFromResource ) +{ + uno::Reference< XFrame > xFrame( m_xOwnerWeak.get(), UNO_QUERY ); + if ( xFrame.is() ) + { + uno::Reference< ::com::sun::star::awt::XWindow >xContainerWindow = xFrame->getContainerWindow(); + Window* pWindow = NULL; + + // Use SolarMutex for threadsafe code too! + SolarMutexGuard aSolarGuard; + { + pWindow = VCLUnoHelper::GetWindow( xContainerWindow ); + while ( pWindow && !pWindow->IsSystemWindow() ) + pWindow = pWindow->GetParent(); + } + + if ( pWindow ) + { + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + + SystemWindow* pSysWindow = (SystemWindow *)pWindow; + + if ( m_pMenuManager ) + { + // remove old menu from our system window if it was set before + if ( m_pMenuManager->GetMenu() == (Menu *)pSysWindow->GetMenuBar() ) + pSysWindow->SetMenuBar( NULL ); + + // remove listener before we destruct ourself, so we cannot be called back afterwards + m_pMenuManager->RemoveListener(); + + SAL_STATIC_CAST( ::com::sun::star::uno::XInterface*, (OWeakObject*)m_pMenuManager )->release(); + + m_pMenuManager = 0; + } + + if ( pMenuBar != NULL ) + { + USHORT nPos = pMenuBar->GetItemPos( SLOTID_MDIWINDOWLIST ); + if ( nPos != MENU_ITEM_NOTFOUND ) + { + OUString aNoContext; + + uno::Reference< XModel > xModel; + uno::Reference< XController > xController( xFrame->getController(), UNO_QUERY ); + + if ( xController.is() ) + xModel = uno::Reference< XModel >( xController->getModel(), UNO_QUERY ); + + // retrieve addon popup menus and add them to our menu bar + AddonMenuManager::MergeAddonPopupMenus( xFrame, xModel, nPos, pMenuBar ); + + // retrieve addon help menu items and add them to our help menu + AddonMenuManager::MergeAddonHelpMenu( xFrame, pMenuBar ); + } + + // set new menu on our system window and create new menu manager + if ( bMenuFromResource ) + { + // #110897# + // m_pMenuManager = new MenuManager( xFrame, pMenuBar, sal_True, sal_False ); + m_pMenuManager = new MenuManager( m_xFactory, xFrame, pMenuBar, sal_True, sal_False ); + } + else + { + // #110897# + // m_pMenuManager = new MenuManager( xFrame, pMenuBar, sal_True, sal_True ); + m_pMenuManager = new MenuManager( m_xFactory, xFrame, pMenuBar, sal_True, sal_True ); + } + + pSysWindow->SetMenuBar( pMenuBar ); + } + + return sal_True; + } + } + + return sal_False; +} + +IMPL_LINK( MenuDispatcher, Close_Impl, void*, EMPTYARG ) +{ + css::uno::Reference < css::frame::XFrame > xFrame( m_xOwnerWeak.get(), css::uno::UNO_QUERY ); + if ( !xFrame.is() ) + return 0; + + css::util::URL aURL; + aURL.Complete = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(".uno:CloseWin")); + css::uno::Reference< css::util::XURLTransformer > xTrans ( m_xFactory->createInstance( + SERVICENAME_URLTRANSFORMER ), css::uno::UNO_QUERY ); + if( xTrans.is() ) + { + // Datei laden + xTrans->parseStrict( aURL ); + uno::Reference< XDispatchProvider > xProv( xFrame, UNO_QUERY ); + if ( xProv.is() ) + { + css::uno::Reference < css::frame::XDispatch > aDisp = xProv->queryDispatch( aURL, ::rtl::OUString(), 0 ); + if ( aDisp.is() ) + aDisp->dispatch( aURL, css::uno::Sequence < css::beans::PropertyValue>() ); + } + } + + return 0; +} + + +//_________________________________________________________________________________________________________________ +// debug methods +//_________________________________________________________________________________________________________________ + +/*----------------------------------------------------------------------------------------------------------------- + The follow methods checks the parameter for other functions. If a parameter or his value is non valid, + we return "sal_False". (else sal_True) This mechanism is used to throw an ASSERT! + + ATTENTION + + If you miss a test for one of this parameters, contact the autor or add it himself !(?) + But ... look for right testing! See using of this methods! +-----------------------------------------------------------------------------------------------------------------*/ + +#ifdef ENABLE_ASSERTIONS + +//***************************************************************************************************************** +sal_Bool MenuDispatcher::impldbg_checkParameter_MenuDispatcher( const uno::Reference< XMultiServiceFactory >& xFactory , + const uno::Reference< XFrame >& xOwner ) +{ + // Set default return value. + sal_Bool bOK = sal_True; + // Check parameter. + if ( + ( &xFactory == NULL ) || + ( &xOwner == NULL ) || + ( xFactory.is() == sal_False ) || + ( xOwner.is() == sal_False ) + ) + { + bOK = sal_False ; + } + // Return result of check. + return bOK ; +} + +//***************************************************************************************************************** +// We need a valid URL. What is meaning with "register for nothing"?! +// xControl must correct to - nobody can advised otherwise! +sal_Bool MenuDispatcher::impldbg_checkParameter_addStatusListener( const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) +{ + // Set default return value. + sal_Bool bOK = sal_True; + // Check parameter. + if ( + ( &xControl == NULL ) || + ( &aURL == NULL ) || + ( aURL.Complete.getLength() < 1 ) + ) + { + bOK = sal_False ; + } + // Return result of check. + return bOK ; +} + +//***************************************************************************************************************** +// The same goes for these case! We have added valid listener for correct URL only. +// We can't remove invalid listener for nothing! +sal_Bool MenuDispatcher::impldbg_checkParameter_removeStatusListener( const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) +{ + // Set default return value. + sal_Bool bOK = sal_True; + // Check parameter. + if ( + ( &xControl == NULL ) || + ( &aURL == NULL ) || + ( aURL.Complete.getLength() < 1 ) + ) + { + bOK = sal_False ; + } + // Return result of check. + return bOK ; +} + +#endif // #ifdef ENABLE_ASSERTIONS + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/oxt_handler.cxx b/framework/source/dispatch/oxt_handler.cxx new file mode 100644 index 000000000000..695fea4b3d81 --- /dev/null +++ b/framework/source/dispatch/oxt_handler.cxx @@ -0,0 +1,283 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ + +#include <dispatch/oxt_handler.hxx> + +#include <threadhelp/transactionguard.hxx> + +#include <threadhelp/writeguard.hxx> + +#include <threadhelp/readguard.hxx> + +#include <macros/debug.hxx> + +#include <services.h> + +#include <comphelper/mediadescriptor.hxx> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ + +#include <com/sun/star/io/XInputStream.hpp> +#include <com/sun/star/frame/DispatchResultState.hpp> +#include <com/sun/star/task/XJobExecutor.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <comphelper/sequenceashashmap.hxx> + +#include <rtl/ustrbuf.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +#define UNISTRING(s) rtl::OUString(RTL_CONSTASCII_USTRINGPARAM(s)) + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//***************************************************************************************************************** +// XInterface, XTypeProvider, XServiceInfo +//***************************************************************************************************************** +DEFINE_XINTERFACE_5 ( Oxt_Handler , + OWeakObject , + DIRECT_INTERFACE( css::lang::XTypeProvider ), + DIRECT_INTERFACE( css::lang::XServiceInfo ), + DIRECT_INTERFACE( css::frame::XNotifyingDispatch ), + DIRECT_INTERFACE( css::frame::XDispatch ), + DIRECT_INTERFACE( css::document::XExtendedFilterDetection ) + ) + +DEFINE_XTYPEPROVIDER_5 ( Oxt_Handler , + css::lang::XTypeProvider , + css::lang::XServiceInfo , + css::frame::XNotifyingDispatch , + css::frame::XDispatch , + css::document::XExtendedFilterDetection + ) + +DEFINE_XSERVICEINFO_MULTISERVICE ( Oxt_Handler , + ::cppu::OWeakObject , + SERVICENAME_CONTENTHANDLER , + IMPLEMENTATIONNAME_OXT_HANDLER + ) + +DEFINE_INIT_SERVICE ( Oxt_Handler, + { + } + ) + +/*-************************************************************************************************************//** + @short standard ctor + @descr These initialize a new instance of this class with needed informations for work. + + @seealso using at owner + + @param "xFactory", reference to service manager for creation of new services + @return - + + @onerror Show an assertion and do nothing else. + @threadsafe yes +*//*-*************************************************************************************************************/ +Oxt_Handler::Oxt_Handler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory ) + // Init baseclasses first + : ThreadHelpBase ( ) + , ::cppu::OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) +{ +} + +/*-************************************************************************************************************//** + @short standard dtor + @descr - + + @seealso - + + @param - + @return - + + @onerror - + @threadsafe - +*//*-*************************************************************************************************************/ +Oxt_Handler::~Oxt_Handler() +{ + if ( m_xListener.is() ) + { + css::frame::DispatchResultEvent aEvent; + aEvent.State = css::frame::DispatchResultState::FAILURE; + m_xListener->dispatchFinished( aEvent ); + m_xListener = css::uno::Reference< css::frame::XDispatchResultListener >(); + } +} + +/*-************************************************************************************************************//** + @interface ::com::sun::star::frame::XDispatch + + @short try to load audio file + @descr This method try to load given audio file by URL and play it. We use vcl/Sound class to do that. + Playing of sound is asynchron everytime. + + @attention We must hold us alive by ourself ... because we use async. vcl sound player ... but playing is started + in async interface call "dispatch()" too. And caller forget us imediatly. But then our uno ref count + will decreased to 0 and will die. The only solution is to use own reference to our implementation. + But we do it for realy started jobs only and release it during call back of vcl. + + @seealso class vcl/Sound + @seealso method implts_PlayerNotify() + + @param "aURL" , URL to dispatch. + @param "lArguments", list of optional arguments. + @return - + + @onerror We do nothing. + @threadsafe yes +*//*-*************************************************************************************************************/ +void SAL_CALL Oxt_Handler::dispatchWithNotification( const css::util::URL& aURL, + const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) + throw( css::uno::RuntimeException ) +{ + // SAFE { + ResetableGuard aLock( m_aLock ); + + rtl::OUString sServiceName = UNISTRING( "com.sun.star.deployment.ui.PackageManagerDialog" ); + css::uno::Sequence< css::uno::Any > lParams(1); + lParams[0] <<= aURL.Main; + + css::uno::Reference< css::uno::XInterface > xService; + + xService = m_xFactory->createInstanceWithArguments( sServiceName, lParams ); + css::uno::Reference< css::task::XJobExecutor > xExecuteable( xService, css::uno::UNO_QUERY ); + if ( xExecuteable.is() ) + xExecuteable->trigger( rtl::OUString() ); + + if ( xListener.is() ) + { + css::frame::DispatchResultEvent aEvent; + aEvent.State = css::frame::DispatchResultState::SUCCESS; + xListener->dispatchFinished( aEvent ); + } + +/* + // Try to initialize player. + m_xListener = xListener; + if (m_aPlayer.SetSoundName(aURL.Complete)) + { + // OK- we can start async playing ... + // Count this request and initialize self-holder against dieing by uno ref count ... + m_xSelfHold = css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + m_aPlayer.Play(); + } +*/ + // } SAFE + aLock.unlock(); +} + +void SAL_CALL Oxt_Handler::dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) + throw( css::uno::RuntimeException ) +{ + dispatchWithNotification( aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >() ); +} + +/*-************************************************************************************************************//** + @interface ::com::sun::star::document::XExtendedFilterDetection + + @short try to detect file (given as argument included in "lDescriptor") + @descr We try to detect, if given file could be handled by this class and is a well known one. + If it is - we return right internal type name - otherwise we return nothing! + So call can search for another detect service and ask him too. + + @attention a) We don't need any mutex here ... because we don't use any member! + b) Dont' use internal player instance "m_pPlayer" to detect given sound file! + It's not neccessary to do that ... and we can use temp. variable to do the same. + This way is easy - we don't must synchronize it with currently played sounds! + Another reason to do so ... We are a listener on our internal ma_Player object. + If you would call "IsSoundFile()" on this instance, he would call us back and + we make some uneccssary things ... + + @seealso - + + @param "lDescriptor", description of file to detect + @return Internal type name which match this file ... or nothing if it is unknown. + + @onerror We return nothing. + @threadsafe yes +*//*-*************************************************************************************************************/ +::rtl::OUString SAL_CALL Oxt_Handler::detect( css::uno::Sequence< css::beans::PropertyValue >& lDescriptor ) + throw( css::uno::RuntimeException ) +{ + // Our default is "nothing". So we can return it, if detection failed or fily type is realy unknown. + ::rtl::OUString sTypeName; + + // Analyze given descriptor to find filename or input stream or ... + ::comphelper::MediaDescriptor aDescriptor( lDescriptor ); + ::rtl::OUString sURL = aDescriptor.getUnpackedValueOrDefault( ::comphelper::MediaDescriptor::PROP_URL(), ::rtl::OUString() ); + + long nLength = sURL.getLength(); + if ( ( nLength > 4 ) && sURL.matchIgnoreAsciiCase( UNISTRING(".oxt"), nLength-4 ) ) + { + // "IsSoundFile" idffer between different "wav" and "au" file versions ... + // couldn't return this information ... because: He use the OS to detect it! + // I think we can the following ones: + // a) look for given extension of url to map our type decision HARD CODED!!! + // b) return preferred type every time... it's easy :-) + sTypeName = ::rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("oxt_OpenOffice_Extension")); + aDescriptor[::comphelper::MediaDescriptor::PROP_TYPENAME()] <<= sTypeName; + aDescriptor >> lDescriptor; + } + + // Return our decision. + return sTypeName; +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/popupmenudispatcher.cxx b/framework/source/dispatch/popupmenudispatcher.cxx new file mode 100644 index 000000000000..96c57d78c3fe --- /dev/null +++ b/framework/source/dispatch/popupmenudispatcher.cxx @@ -0,0 +1,422 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ + +#include <dispatch/popupmenudispatcher.hxx> +#include <general.h> +#include <xml/menuconfiguration.hxx> +#include <classes/addonmenu.hxx> +#include <services.h> +#include <properties.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/frame/FrameSearchFlag.hpp> +#include <com/sun/star/awt/XToolkit.hpp> +#include <com/sun/star/awt/WindowAttribute.hpp> +#include <com/sun/star/awt/WindowDescriptor.hpp> +#include <com/sun/star/awt/PosSize.hpp> +#include <com/sun/star/awt/XWindowPeer.hpp> +#include <com/sun/star/beans/UnknownPropertyException.hpp> +#include <com/sun/star/lang/WrappedTargetException.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/container/XEnumeration.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <ucbhelper/content.hxx> +#include <osl/mutex.hxx> +#include <rtl/ustrbuf.hxx> +#include <vcl/svapp.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +using namespace ::com::sun::star ; +using namespace ::com::sun::star::awt ; +using namespace ::com::sun::star::beans ; +using namespace ::com::sun::star::container ; +using namespace ::com::sun::star::frame ; +using namespace ::com::sun::star::lang ; +using namespace ::com::sun::star::uno ; +using namespace ::com::sun::star::util ; +using namespace ::cppu ; +using namespace ::osl ; +using namespace ::rtl ; + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ +const char* PROTOCOL_VALUE = "vnd.sun.star.popup:"; +const sal_Int32 PROTOCOL_LENGTH = 19; + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//***************************************************************************************************************** +// constructor +//***************************************************************************************************************** +PopupMenuDispatcher::PopupMenuDispatcher( + const uno::Reference< XMultiServiceFactory >& xFactory ) + // Init baseclasses first + : ThreadHelpBase ( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) + , m_aListenerContainer ( m_aLock.getShareableOslMutex() ) + , m_bAlreadyDisposed ( sal_False ) + , m_bActivateListener ( sal_False ) +{ +} + +//***************************************************************************************************************** +// destructor +//***************************************************************************************************************** +PopupMenuDispatcher::~PopupMenuDispatcher() +{ + // Warn programmer if he forgot to dispose this instance. + // We must release all our references ... + // and a dtor isn't the best place to do that! +} + +//***************************************************************************************************************** +// XInterface, XTypeProvider +//***************************************************************************************************************** +DEFINE_XINTERFACE_7 ( PopupMenuDispatcher , + ::cppu::OWeakObject , + DIRECT_INTERFACE( XTypeProvider ), + DIRECT_INTERFACE( XServiceInfo ), + DIRECT_INTERFACE( XDispatchProvider ), + DIRECT_INTERFACE( XDispatch ), + DIRECT_INTERFACE( XEventListener ), + DIRECT_INTERFACE( XInitialization ), + DERIVED_INTERFACE( XFrameActionListener, XEventListener ) + ) + +DEFINE_XTYPEPROVIDER_7 ( PopupMenuDispatcher , + XTypeProvider , + XServiceInfo , + XDispatchProvider , + XDispatch , + XEventListener , + XInitialization , + XFrameActionListener + ) + +DEFINE_XSERVICEINFO_MULTISERVICE( PopupMenuDispatcher , + ::cppu::OWeakObject , + SERVICENAME_PROTOCOLHANDLER , + IMPLEMENTATIONNAME_POPUPMENUDISPATCHER ) + +DEFINE_INIT_SERVICE(PopupMenuDispatcher, +{ + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ +} +) + +//***************************************************************************************************************** +// XInitialization +//***************************************************************************************************************** +void SAL_CALL PopupMenuDispatcher::initialize( + const css::uno::Sequence< css::uno::Any >& lArguments ) +throw( css::uno::Exception, css::uno::RuntimeException) +{ + css::uno::Reference< css::frame::XFrame > xFrame; + + /* SAFE { */ + WriteGuard aWriteLock(m_aLock); + + for (int a=0; a<lArguments.getLength(); ++a) + { + if (a==0) + { + lArguments[a] >>= xFrame; + m_xWeakFrame = xFrame; + + m_bActivateListener = sal_True; + uno::Reference< css::frame::XFrameActionListener > xFrameActionListener( + (OWeakObject *)this, css::uno::UNO_QUERY ); + xFrame->addFrameActionListener( xFrameActionListener ); + } + } + + aWriteLock.unlock(); + /* } SAFE */ +} + +//***************************************************************************************************************** +// XDispatchProvider +//***************************************************************************************************************** +css::uno::Reference< css::frame::XDispatch > +SAL_CALL PopupMenuDispatcher::queryDispatch( + const css::util::URL& rURL , + const ::rtl::OUString& sTarget , + sal_Int32 nFlags ) +throw( css::uno::RuntimeException ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatch; + + if ( rURL.Complete.compareToAscii( PROTOCOL_VALUE, PROTOCOL_LENGTH ) == 0 ) + { + // --- SAFE --- + ResetableGuard aGuard( m_aLock ); + impl_RetrievePopupControllerQuery(); + impl_CreateUriRefFactory(); + + css::uno::Reference< css::container::XNameAccess > xPopupCtrlQuery( m_xPopupCtrlQuery ); + css::uno::Reference< css::uri::XUriReferenceFactory > xUriRefFactory( m_xUriRefFactory ); + aGuard.unlock(); + // --- SAFE --- + + if ( xPopupCtrlQuery.is() ) + { + try + { + // Just use the main part of the URL for popup menu controllers + sal_Int32 nQueryPart( 0 ); + sal_Int32 nSchemePart( 0 ); + rtl::OUString aBaseURL( RTL_CONSTASCII_USTRINGPARAM( "vnd.sun.star.popup:" )); + rtl::OUString aURL( rURL.Complete ); + + nSchemePart = aURL.indexOf( ':' ); + if (( nSchemePart > 0 ) && + ( aURL.getLength() > ( nSchemePart+1 ))) + { + nQueryPart = aURL.indexOf( '?', nSchemePart ); + if ( nQueryPart > 0 ) + aBaseURL += aURL.copy( nSchemePart+1, nQueryPart-(nSchemePart+1) ); + else if ( nQueryPart == -1 ) + aBaseURL += aURL.copy( nSchemePart+1 ); + } + + css::uno::Reference< css::frame::XDispatchProvider > xDispatchProvider; + + // Find popup menu controller using the base URL + xPopupCtrlQuery->getByName( aBaseURL ) >>= xDispatchProvider; + aGuard.unlock(); + + // Ask popup menu dispatch provider for dispatch object + if ( xDispatchProvider.is() ) + xDispatch = xDispatchProvider->queryDispatch( rURL, sTarget, nFlags ); + } + catch ( RuntimeException& ) + { + throw; + } + catch ( Exception& ) + { + } + } + } + return xDispatch; +} + +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL +PopupMenuDispatcher::queryDispatches( + const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) +throw( css::uno::RuntimeException ) +{ + sal_Int32 nCount = lDescriptor.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = this->queryDispatch( + lDescriptor[i].FeatureURL, + lDescriptor[i].FrameName, + lDescriptor[i].SearchFlags); + } + return lDispatcher; +} + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void +SAL_CALL PopupMenuDispatcher::dispatch( + const URL& /*aURL*/ , + const Sequence< PropertyValue >& /*seqProperties*/ ) +throw( RuntimeException ) +{ +} + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void +SAL_CALL PopupMenuDispatcher::addStatusListener( + const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) +throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + // Add listener to container. + m_aListenerContainer.addInterface( aURL.Complete, xControl ); +} + +//***************************************************************************************************************** +// XDispatch +//***************************************************************************************************************** +void +SAL_CALL PopupMenuDispatcher::removeStatusListener( + const uno::Reference< XStatusListener >& xControl, + const URL& aURL ) +throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + // Add listener to container. + m_aListenerContainer.removeInterface( aURL.Complete, xControl ); +} + +//***************************************************************************************************************** +// XFrameActionListener +//***************************************************************************************************************** + +void +SAL_CALL PopupMenuDispatcher::frameAction( + const FrameActionEvent& aEvent ) +throw ( RuntimeException ) +{ + ResetableGuard aGuard( m_aLock ); + + if (( aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING ) || + ( aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED )) + { + // Reset query reference to requery it again next time + m_xPopupCtrlQuery.clear(); + } +} + +//***************************************************************************************************************** +// XEventListener +//***************************************************************************************************************** +void +SAL_CALL PopupMenuDispatcher::disposing( const EventObject& ) throw( RuntimeException ) +{ + // Ready for multithreading + ResetableGuard aGuard( m_aLock ); + // Safe impossible cases + LOG_ASSERT( !(m_bAlreadyDisposed==sal_True), "MenuDispatcher::disposing()\nObject already disposed .. don't call it again!\n" ) + + if( m_bAlreadyDisposed == sal_False ) + { + m_bAlreadyDisposed = sal_True; + + if ( m_bActivateListener ) + { + uno::Reference< XFrame > xFrame( m_xWeakFrame.get(), UNO_QUERY ); + if ( xFrame.is() ) + { + xFrame->removeFrameActionListener( uno::Reference< XFrameActionListener >( (OWeakObject *)this, UNO_QUERY )); + m_bActivateListener = sal_False; + } + } + + // Forget our factory. + m_xFactory = uno::Reference< XMultiServiceFactory >(); + } +} + +void PopupMenuDispatcher::impl_RetrievePopupControllerQuery() +{ + if ( !m_xPopupCtrlQuery.is() ) + { + css::uno::Reference< css::frame::XLayoutManager > xLayoutManager; + css::uno::Reference< css::frame::XFrame > xFrame( m_xWeakFrame ); + + if ( xFrame.is() ) + { + css::uno::Reference< css::beans::XPropertySet > xPropSet( xFrame, css::uno::UNO_QUERY ); + if ( xPropSet.is() ) + { + try + { + xPropSet->getPropertyValue( FRAME_PROPNAME_LAYOUTMANAGER ) >>= xLayoutManager; + + if ( xLayoutManager.is() ) + { + css::uno::Reference< css::ui::XUIElement > xMenuBar; + rtl::OUString aMenuBar( RTL_CONSTASCII_USTRINGPARAM( "private:resource/menubar/menubar" )); + xMenuBar = xLayoutManager->getElement( aMenuBar ); + + m_xPopupCtrlQuery = css::uno::Reference< css::container::XNameAccess >( + xMenuBar, css::uno::UNO_QUERY ); + } + } + catch ( css::uno::RuntimeException& ) + { + throw; + } + catch ( css::uno::Exception& ) + { + } + } + } + } +} + +void PopupMenuDispatcher::impl_CreateUriRefFactory() +{ + if ( !m_xUriRefFactory.is() ) + { + rtl::OUString aUriRefFactoryService( + RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.uri.UriReferenceFactory" )); + + m_xUriRefFactory = css::uno::Reference< css::uri::XUriReferenceFactory >( + m_xFactory->createInstance( aUriRefFactoryService ), + css::uno::UNO_QUERY); + + } +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/servicehandler.cxx b/framework/source/dispatch/servicehandler.cxx new file mode 100644 index 000000000000..6f019f247775 --- /dev/null +++ b/framework/source/dispatch/servicehandler.cxx @@ -0,0 +1,354 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/servicehandler.hxx> +#include <threadhelp/readguard.hxx> +#include <general.h> +#include <services.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/frame/DispatchResultState.hpp> +#include <com/sun/star/task/XJobExecutor.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <vcl/svapp.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +#define PROTOCOL_VALUE "service:" +#define PROTOCOL_LENGTH 8 + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// XInterface, XTypeProvider, XServiceInfo + +DEFINE_XINTERFACE_5(ServiceHandler , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::lang::XServiceInfo ), + DIRECT_INTERFACE(css::frame::XDispatchProvider ), + DIRECT_INTERFACE(css::frame::XNotifyingDispatch), + DIRECT_INTERFACE(css::frame::XDispatch )) + +DEFINE_XTYPEPROVIDER_5(ServiceHandler , + css::lang::XTypeProvider , + css::lang::XServiceInfo , + css::frame::XDispatchProvider , + css::frame::XNotifyingDispatch, + css::frame::XDispatch ) + +DEFINE_XSERVICEINFO_MULTISERVICE(ServiceHandler , + ::cppu::OWeakObject , + SERVICENAME_PROTOCOLHANDLER , + IMPLEMENTATIONNAME_SERVICEHANDLER) + +DEFINE_INIT_SERVICE(ServiceHandler, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + } + ) + +//_________________________________________________________________________________________________________________ + +/** + @short standard ctor + @descr These initialize a new instance of ths class with needed informations for work. + + @param xFactory + reference to uno servicemanager for creation of new services + + @modified 02.05.2002 08:16, as96863 +*/ +ServiceHandler::ServiceHandler( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory ) + // Init baseclasses first + : ThreadHelpBase( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) +{ +} + +//_________________________________________________________________________________________________________________ + +/** + @short standard dtor + @descr - + + @modified 02.05.2002 08:16, as96863 +*/ +ServiceHandler::~ServiceHandler() +{ + m_xFactory = NULL; +} + +//_________________________________________________________________________________________________________________ + +/** + @short decide if this dispatch implementation can be used for requested URL or not + @descr A protocol handler is registerd for an URL pattern inside configuration and will + be asked by the generic dispatch mechanism inside framework, if he can handle this + special URL wich match his registration. He can agree by returning of a valid dispatch + instance or disagree by returning <NULL/>. + We don't create new dispatch instances here realy - we return THIS as result to handle it + at the same implementation. + + @modified 02.05.2002 15:25, as96863 +*/ +css::uno::Reference< css::frame::XDispatch > SAL_CALL ServiceHandler::queryDispatch( const css::util::URL& aURL , + const ::rtl::OUString& /*sTarget*/ , + sal_Int32 /*nFlags*/ ) throw( css::uno::RuntimeException ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0) + xDispatcher = this; + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short do the same like dispatch() but for multiple requests at the same time + @descr - + + @modified 02.05.2002 15:27, as96863 +*/ +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL ServiceHandler::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException ) +{ + sal_Int32 nCount = lDescriptor.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = this->queryDispatch( + lDescriptor[i].FeatureURL, + lDescriptor[i].FrameName, + lDescriptor[i].SearchFlags); + } + return lDispatcher; +} + +//_________________________________________________________________________________________________________________ + +/** + @short dispatch URL with arguments + @descr We use threadsafe internal method to do so. It returns a state value - but we ignore it. + Because we doesn't support status listener notifications here. + + @param aURL + uno URL which should be executed + @param lArguments + list of optional arguments for this request + + @modified 02.05.2002 08:19, as96863 +*/ +void SAL_CALL ServiceHandler::dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException ) +{ + // dispatch() is an [oneway] call ... and may our user release his reference to us immediatly. + // So we should hold us self alive till this call ends. + css::uno::Reference< css::frame::XNotifyingDispatch > xSelfHold(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + implts_dispatch(aURL,lArguments); + // No notification for status listener! +} + +//_________________________________________________________________________________________________________________ + +/** + @short dispatch with guaranteed notifications about success + @descr We use threadsafe internal method to do so. Return state of this function will be used + for notification if an optional listener is given. + + @param aURL + uno URL which should be executed + @param lArguments + list of optional arguments for this request + @param xListener + optional listener for state events + + @modified 30.04.2002 14:49, as96863 +*/ +void SAL_CALL ServiceHandler::dispatchWithNotification( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException ) +{ + // This class was designed to die by reference. And if user release his reference to us immediatly after calling this method + // we can run into some problems. So we hold us self alive till this method ends. + // Another reason: We can use this reference as source of sending event at the end too. + css::uno::Reference< css::frame::XNotifyingDispatch > xThis(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY); + + css::uno::Reference< css::uno::XInterface > xService = implts_dispatch(aURL,lArguments); + if (xListener.is()) + { + css::frame::DispatchResultEvent aEvent; + if (xService.is()) + aEvent.State = css::frame::DispatchResultState::SUCCESS; + else + aEvent.State = css::frame::DispatchResultState::FAILURE; + aEvent.Result <<= xService; // may NULL for state=FAILED! + aEvent.Source = xThis; + + xListener->dispatchFinished( aEvent ); + } +} + +//_________________________________________________________________________________________________________________ + +/** + @short threadsafe helper for dispatch calls + @descr We support two interfaces for the same process - dispatch URLs. That the reason for this internal + function. It implements the real dispatch operation and returns a state value which inform caller + about success. He can notify listener then by using this return value. + + @param aURL + uno URL which should be executed + @param lArguments + list of optional arguments for this request + + @return <NULL/> if requested service couldn't be created successullfy; + a valid reference otherwise. This return value can be used to indicate, + if dispatch was successfully or not. + + @modified 02.05.2002 10:51, as96863 +*/ +css::uno::Reference< css::uno::XInterface > ServiceHandler::implts_dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/ ) throw( css::uno::RuntimeException ) +{ + /* SAFE */ + ReadGuard aReadLock( m_aLock ); + css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory; + aReadLock.unlock(); + /* SAFE */ + + if (!xFactory.is()) + return css::uno::Reference< css::uno::XInterface >(); + + // extract service name and may optional given parameters from given URL + // and use it to create and start the component + ::rtl::OUString sServiceAndArguments = aURL.Complete.copy(PROTOCOL_LENGTH); + ::rtl::OUString sServiceName; + ::rtl::OUString sArguments ; + + sal_Int32 nArgStart = sServiceAndArguments.indexOf('?',0); + if (nArgStart!=-1) + { + sServiceName = sServiceAndArguments.copy(0,nArgStart); + ++nArgStart; // ignore '?'! + sArguments = sServiceAndArguments.copy(nArgStart); + } + else + { + sServiceName = sServiceAndArguments; + } + + if (!sServiceName.getLength()) + return css::uno::Reference< css::uno::XInterface >(); + + // If a service doesnt support an optional job executor interface - he can't get + // any given parameters! + // Because we can't know if we must call createInstanceWithArguments() or XJobExecutor::trigger() ... + + css::uno::Reference< css::uno::XInterface > xService; + try + { + // => a) a service starts running inside his own ctor and we create it only + xService = xFactory->createInstance(sServiceName); + // or b) he implements the right interface and starts there (may with optional parameters) + css::uno::Reference< css::task::XJobExecutor > xExecuteable(xService, css::uno::UNO_QUERY); + if (xExecuteable.is()) + xExecuteable->trigger(sArguments); + } + // ignore all errors - inclusive runtime errors! + // E.g. a script based service (written in phyton) could not be executed + // because it contains syntax errors, which was detected at runtime ... + catch(const css::uno::Exception&) + { xService.clear(); } + + return xService; +} + +//_________________________________________________________________________________________________________________ + +/** + @short add/remove listener for state events + @descr We use an internal container to hold such registered listener. This container lives if we live. + And if call pas registration as non breakable transaction - we can accept the request without + any explicit lock. Because we share our mutex with this container. + + @param xListener + reference to a valid listener for state events + @param aURL + URL about listener will be informed, if something occurred + + @modified 30.04.2002 14:49, as96863 +*/ +void SAL_CALL ServiceHandler::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ , + const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL ServiceHandler::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/ , + const css::util::URL& /*aURL*/ ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/startmoduledispatcher.cxx b/framework/source/dispatch/startmoduledispatcher.cxx new file mode 100644 index 000000000000..755935a3a5bd --- /dev/null +++ b/framework/source/dispatch/startmoduledispatcher.cxx @@ -0,0 +1,244 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +#include <dispatch/startmoduledispatcher.hxx> + +//_______________________________________________ +// my own includes + +#include <pattern/frame.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <classes/framelistanalyzer.hxx> +#include <dispatchcommands.h> +#include <targets.h> +#include <services.h> +#include <general.h> + +//_______________________________________________ +// interface includes +#include <com/sun/star/frame/XDesktop.hpp> +#include <com/sun/star/frame/XController.hpp> +#include <com/sun/star/frame/CommandGroup.hpp> +#include <com/sun/star/awt/XTopWindow.hpp> +#include "com/sun/star/beans/XFastPropertySet.hpp" +#include <com/sun/star/frame/XModuleManager.hpp> + +//_______________________________________________ +// includes of other projects +#include <toolkit/helper/vclunohelper.hxx> +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <osl/mutex.hxx> +#include <unotools/moduleoptions.hxx> + +//_______________________________________________ +// namespace + +namespace framework{ + +#ifdef fpf + #error "Who uses \"fpf\" as define. It will overwrite my namespace alias ..." +#endif +namespace fpf = ::framework::pattern::frame; + +//_______________________________________________ +// declarations + +DEFINE_XINTERFACE_4(StartModuleDispatcher , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::frame::XNotifyingDispatch ), + DIRECT_INTERFACE(css::frame::XDispatch ), + DIRECT_INTERFACE(css::frame::XDispatchInformationProvider)) + +// Note: XStatusListener is an implementation detail. Hide it for scripting! +DEFINE_XTYPEPROVIDER_4(StartModuleDispatcher , + css::lang::XTypeProvider , + css::frame::XDispatchInformationProvider, + css::frame::XNotifyingDispatch , + css::frame::XDispatch ) + +//----------------------------------------------- +StartModuleDispatcher::StartModuleDispatcher(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame , + const ::rtl::OUString& sTarget) + : ThreadHelpBase (&Application::GetSolarMutex() ) + , ::cppu::OWeakObject( ) + , m_xSMGR (xSMGR ) + , m_xOwner (xFrame ) + , m_sDispatchTarget (sTarget ) + , m_lStatusListener (m_aLock.getShareableOslMutex()) +{ +} + +//----------------------------------------------- +StartModuleDispatcher::~StartModuleDispatcher() +{ +} + +//----------------------------------------------- +void SAL_CALL StartModuleDispatcher::dispatch(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments) + throw(css::uno::RuntimeException) +{ + dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >()); +} + +//----------------------------------------------- +void SAL_CALL StartModuleDispatcher::dispatchWithNotification(const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& /*lArguments*/, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) + throw(css::uno::RuntimeException) +{ + ::sal_Int16 nResult = css::frame::DispatchResultState::DONTKNOW; + if (aURL.Complete.equalsAsciiL(RTL_CONSTASCII_STRINGPARAM(CMD_UNO_SHOWSTARTMODULE))) + { + nResult = css::frame::DispatchResultState::FAILURE; + if (implts_isBackingModePossible ()) + { + if (implts_establishBackingMode ()) + nResult = css::frame::DispatchResultState::SUCCESS; + } + } + + implts_notifyResultListener(xListener, nResult, css::uno::Any()); +} + +//----------------------------------------------- +css::uno::Sequence< ::sal_Int16 > SAL_CALL StartModuleDispatcher::getSupportedCommandGroups() + throw(css::uno::RuntimeException) +{ + return css::uno::Sequence< ::sal_Int16 >(); +} + +//----------------------------------------------- +css::uno::Sequence< css::frame::DispatchInformation > SAL_CALL StartModuleDispatcher::getConfigurableDispatchInformation(::sal_Int16 /*nCommandGroup*/) + throw(css::uno::RuntimeException) +{ + return css::uno::Sequence< css::frame::DispatchInformation >(); +} + +//----------------------------------------------- +void SAL_CALL StartModuleDispatcher::addStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +void SAL_CALL StartModuleDispatcher::removeStatusListener(const css::uno::Reference< css::frame::XStatusListener >& /*xListener*/, + const css::util::URL& /*aURL*/ ) + throw(css::uno::RuntimeException) +{ +} + +//----------------------------------------------- +::sal_Bool StartModuleDispatcher::implts_isBackingModePossible () +{ + if ( ! SvtModuleOptions().IsModuleInstalled(SvtModuleOptions::E_SSTARTMODULE)) + return sal_False; + + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::frame::XFramesSupplier > xDesktop( + xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY); + + FrameListAnalyzer aCheck( + xDesktop, + css::uno::Reference< css::frame::XFrame >(), + FrameListAnalyzer::E_HELP | FrameListAnalyzer::E_BACKINGCOMPONENT); + + ::sal_Bool bIsPossible = sal_False; + ::sal_Int32 nVisibleFrames = aCheck.m_lOtherVisibleFrames.getLength (); + + if ( + ( ! aCheck.m_xBackingComponent.is ()) && + ( nVisibleFrames < 1 ) + ) + { + bIsPossible = sal_True; + } + + return bIsPossible; +} + +//----------------------------------------------- +::sal_Bool StartModuleDispatcher::implts_establishBackingMode() +{ + // SAFE -> ---------------------------------- + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SAFE ---------------------------------- + + css::uno::Reference< css::frame::XFrame > xDesktop (xSMGR->createInstance(SERVICENAME_DESKTOP), css::uno::UNO_QUERY); + css::uno::Reference< css::frame::XFrame > xFrame = xDesktop->findFrame (SPECIALTARGET_BLANK, 0); + css::uno::Reference< css::awt::XWindow > xContainerWindow = xFrame->getContainerWindow (); + + css::uno::Sequence< css::uno::Any > lArgs(1); + lArgs[0] <<= xContainerWindow; + + css::uno::Reference< css::frame::XController > xStartModule( + xSMGR->createInstanceWithArguments(SERVICENAME_STARTMODULE, lArgs), + css::uno::UNO_QUERY_THROW); + + css::uno::Reference< css::awt::XWindow > xComponentWindow(xStartModule, css::uno::UNO_QUERY); + xFrame->setComponent(xComponentWindow, xStartModule); + xStartModule->attachFrame(xFrame); + xContainerWindow->setVisible(sal_True); + + return sal_True; +} + +//----------------------------------------------- +void StartModuleDispatcher::implts_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener, + ::sal_Int16 nState , + const css::uno::Any& aResult ) +{ + if ( ! xListener.is()) + return; + + css::frame::DispatchResultEvent aEvent( + css::uno::Reference< css::uno::XInterface >(static_cast< ::cppu::OWeakObject* >(this), css::uno::UNO_QUERY), + nState, + aResult); + + xListener->dispatchFinished(aEvent); +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/systemexec.cxx b/framework/source/dispatch/systemexec.cxx new file mode 100644 index 000000000000..8f20919ecdb0 --- /dev/null +++ b/framework/source/dispatch/systemexec.cxx @@ -0,0 +1,237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_________________________________________________________________________________________________________________ +// my own includes +//_________________________________________________________________________________________________________________ +#include <dispatch/systemexec.hxx> +#include <threadhelp/readguard.hxx> +#include <general.h> +#include <services.h> + +//_________________________________________________________________________________________________________________ +// interface includes +//_________________________________________________________________________________________________________________ +#include <com/sun/star/system/XSystemShellExecute.hpp> +#include <com/sun/star/util/XStringSubstitution.hpp> +#include <com/sun/star/system/SystemShellExecuteFlags.hpp> +#include <com/sun/star/frame/DispatchResultState.hpp> + +//_________________________________________________________________________________________________________________ +// includes of other projects +//_________________________________________________________________________________________________________________ + +#include <vcl/svapp.hxx> + +//_________________________________________________________________________________________________________________ +// namespace +//_________________________________________________________________________________________________________________ + +namespace framework{ + +//_________________________________________________________________________________________________________________ +// non exported const +//_________________________________________________________________________________________________________________ + +#define PROTOCOL_VALUE "systemexecute:" +#define PROTOCOL_LENGTH 14 + +//_________________________________________________________________________________________________________________ +// non exported definitions +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// declarations +//_________________________________________________________________________________________________________________ + +//_________________________________________________________________________________________________________________ +// XInterface, XTypeProvider, XServiceInfo + +DEFINE_XINTERFACE_5(SystemExec , + OWeakObject , + DIRECT_INTERFACE(css::lang::XTypeProvider ), + DIRECT_INTERFACE(css::lang::XServiceInfo ), + DIRECT_INTERFACE(css::frame::XDispatchProvider ), + DIRECT_INTERFACE(css::frame::XNotifyingDispatch), + DIRECT_INTERFACE(css::frame::XDispatch )) + +DEFINE_XTYPEPROVIDER_5(SystemExec , + css::lang::XTypeProvider , + css::lang::XServiceInfo , + css::frame::XDispatchProvider , + css::frame::XNotifyingDispatch, + css::frame::XDispatch ) + +DEFINE_XSERVICEINFO_MULTISERVICE(SystemExec , + ::cppu::OWeakObject , + SERVICENAME_PROTOCOLHANDLER , + IMPLEMENTATIONNAME_SYSTEMEXEC) + +DEFINE_INIT_SERVICE(SystemExec, + { + /*Attention + I think we don't need any mutex or lock here ... because we are called by our own static method impl_createInstance() + to create a new instance of this class by our own supported service factory. + see macro DEFINE_XSERVICEINFO_MULTISERVICE and "impl_initService()" for further informations! + */ + } + ) + +//_________________________________________________________________________________________________________________ + +SystemExec::SystemExec( const css::uno::Reference< css::lang::XMultiServiceFactory >& xFactory ) + // Init baseclasses first + : ThreadHelpBase( &Application::GetSolarMutex() ) + , OWeakObject ( ) + // Init member + , m_xFactory ( xFactory ) +{ +} + +//_________________________________________________________________________________________________________________ + +SystemExec::~SystemExec() +{ + m_xFactory = NULL; +} + +//_________________________________________________________________________________________________________________ + +css::uno::Reference< css::frame::XDispatch > SAL_CALL SystemExec::queryDispatch( const css::util::URL& aURL , + const ::rtl::OUString&, + sal_Int32 ) throw( css::uno::RuntimeException ) +{ + css::uno::Reference< css::frame::XDispatch > xDispatcher; + if (aURL.Complete.compareToAscii(PROTOCOL_VALUE,PROTOCOL_LENGTH)==0) + xDispatcher = this; + return xDispatcher; +} + +//_________________________________________________________________________________________________________________ + +css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL SystemExec::queryDispatches( const css::uno::Sequence< css::frame::DispatchDescriptor >& lDescriptor ) throw( css::uno::RuntimeException ) +{ + sal_Int32 nCount = lDescriptor.getLength(); + css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > lDispatcher( nCount ); + for( sal_Int32 i=0; i<nCount; ++i ) + { + lDispatcher[i] = this->queryDispatch( + lDescriptor[i].FeatureURL, + lDescriptor[i].FrameName, + lDescriptor[i].SearchFlags); + } + return lDispatcher; +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL SystemExec::dispatch( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) throw( css::uno::RuntimeException ) +{ + dispatchWithNotification(aURL, lArguments, css::uno::Reference< css::frame::XDispatchResultListener >()); +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL SystemExec::dispatchWithNotification( const css::util::URL& aURL , + const css::uno::Sequence< css::beans::PropertyValue >&, + const css::uno::Reference< css::frame::XDispatchResultListener >& xListener ) throw( css::uno::RuntimeException ) +{ + // convert "systemexec:file:///c:/temp/test.html" => "file:///c:/temp/test.html" + sal_Int32 c = aURL.Complete.getLength()-PROTOCOL_LENGTH; + if (c<1) // we dont check for valid URLs here! The system will show an error message ... + { + impl_notifyResultListener(xListener, css::frame::DispatchResultState::FAILURE); + return; + } + ::rtl::OUString sSystemURLWithVariables = aURL.Complete.copy(PROTOCOL_LENGTH, c); + + // SAFE -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::lang::XMultiServiceFactory > xFactory = m_xFactory; + aReadLock.unlock(); + // <- SAFE + + // TODO check security settings ... + + try + { + css::uno::Reference< css::util::XStringSubstitution > xPathSubst( + xFactory->createInstance(SERVICENAME_SUBSTITUTEPATHVARIABLES), + css::uno::UNO_QUERY_THROW); + + ::rtl::OUString sSystemURL = xPathSubst->substituteVariables(sSystemURLWithVariables, sal_True); // sal_True force an exception if unknown variables exists ! + + css::uno::Reference< css::system::XSystemShellExecute > xShell( + xFactory->createInstance(SERVICENAME_SYSTEMSHELLEXECUTE), + css::uno::UNO_QUERY_THROW); + + xShell->execute(sSystemURL, ::rtl::OUString(), css::system::SystemShellExecuteFlags::DEFAULTS); + impl_notifyResultListener(xListener, css::frame::DispatchResultState::SUCCESS); + } + catch(const css::uno::Exception&) + { + impl_notifyResultListener(xListener, css::frame::DispatchResultState::FAILURE); + } +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL SystemExec::addStatusListener( const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL& ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +//_________________________________________________________________________________________________________________ + +void SAL_CALL SystemExec::removeStatusListener( const css::uno::Reference< css::frame::XStatusListener >&, + const css::util::URL& ) throw( css::uno::RuntimeException ) +{ + // not suported yet +} + +//_________________________________________________________________________________________________________________ + +void SystemExec::impl_notifyResultListener(const css::uno::Reference< css::frame::XDispatchResultListener >& xListener, + const sal_Int16 nState ) +{ + if (xListener.is()) + { + css::frame::DispatchResultEvent aEvent; + aEvent.State = nState; + xListener->dispatchFinished(aEvent); + } +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/framework/source/dispatch/windowcommanddispatch.cxx b/framework/source/dispatch/windowcommanddispatch.cxx new file mode 100644 index 000000000000..09efdb3e8ae6 --- /dev/null +++ b/framework/source/dispatch/windowcommanddispatch.cxx @@ -0,0 +1,194 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_framework.hxx" + +//_______________________________________________ +// my own includes + +#include <dispatch/windowcommanddispatch.hxx> +#include <threadhelp/readguard.hxx> +#include <threadhelp/writeguard.hxx> +#include <targets.h> +#include <services.h> + +//_______________________________________________ +// interface includes + +#include <com/sun/star/frame/XDispatchProvider.hpp> +#include <com/sun/star/frame/XDispatch.hpp> +#include <com/sun/star/util/XURLTransformer.hpp> + +//_______________________________________________ +// includes of other projects + +#include <vcl/window.hxx> +#include <vcl/svapp.hxx> +#include <vcl/cmdevt.hxx> +#include <osl/mutex.hxx> +#include <toolkit/helper/vclunohelper.hxx> +#include <rtl/logfile.hxx> + +//_______________________________________________ +// namespace + +namespace framework{ + +namespace css = ::com::sun::star; + +//_______________________________________________ +// declarations + +const ::rtl::OUString WindowCommandDispatch::COMMAND_PREFERENCES(RTL_CONSTASCII_USTRINGPARAM(".uno:OptionsTreeDialog")); +const ::rtl::OUString WindowCommandDispatch::COMMAND_ABOUTBOX(RTL_CONSTASCII_USTRINGPARAM(".uno:About")); + +//----------------------------------------------- +WindowCommandDispatch::WindowCommandDispatch(const css::uno::Reference< css::lang::XMultiServiceFactory >& xSMGR , + const css::uno::Reference< css::frame::XFrame >& xFrame) + : ThreadHelpBase( ) + , m_xSMGR (xSMGR ) + , m_xFrame (xFrame ) + , m_xWindow (xFrame->getContainerWindow()) +{ + impl_startListening(); +} + +//----------------------------------------------- +WindowCommandDispatch::~WindowCommandDispatch() +{ + m_xSMGR.clear(); +} + +//----------------------------------------------- +void SAL_CALL WindowCommandDispatch::disposing(const css::lang::EventObject& /*aSource*/) + throw (css::uno::RuntimeException) +{ + // We hold our window weak ... so there is no need to clear it's reference here. + // The window and we will die by ref count automatically. +} + +//----------------------------------------------- +void WindowCommandDispatch::impl_startListening() +{ + // SYNCHRONIZED -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::awt::XWindow > xWindow( m_xWindow.get(), css::uno::UNO_QUERY ); + aReadLock.unlock(); + // <- SYNCHRONIZED + + if ( ! xWindow.is()) + return; + + // SYNCHRONIZED -> + { + SolarMutexGuard aSolarLock; + + Window* pWindow = VCLUnoHelper::GetWindow(xWindow); + if ( ! pWindow) + return; + + pWindow->AddEventListener( LINK(this, WindowCommandDispatch, impl_notifyCommand) ); + } + // <- SYNCHRONIZED +} + +//----------------------------------------------- +IMPL_LINK(WindowCommandDispatch, impl_notifyCommand, void*, pParam) +{ + if ( ! pParam) + return 0L; + + const VclWindowEvent* pEvent = (VclWindowEvent*)pParam; + if (pEvent->GetId() != VCLEVENT_WINDOW_COMMAND) + return 0L; + + const CommandEvent* pCommand = (CommandEvent*)pEvent->GetData(); + if (pCommand->GetCommand() != COMMAND_SHOWDIALOG) + return 0L; + + const CommandDialogData* pData = pCommand->GetDialogData(); + if ( ! pData) + return 0L; + + const int nCommand = pData->GetDialogId(); + ::rtl::OUString sCommand; + + switch (nCommand) + { + case SHOWDIALOG_ID_PREFERENCES : + sCommand = WindowCommandDispatch::COMMAND_PREFERENCES; + break; + + case SHOWDIALOG_ID_ABOUT : + sCommand = WindowCommandDispatch::COMMAND_ABOUTBOX; + break; + + default : + return 0L; + } + + impl_dispatchCommand(sCommand); + + return 0L; +} + +//----------------------------------------------- +void WindowCommandDispatch::impl_dispatchCommand(const ::rtl::OUString& sCommand) +{ + // ignore all errors here. It's clicking a menu entry only ... + // The user will try it again, in case nothing happens .-) + try + { + // SYNCHRONIZED -> + ReadGuard aReadLock(m_aLock); + css::uno::Reference< css::frame::XDispatchProvider > xProvider(m_xFrame.get(), css::uno::UNO_QUERY_THROW); + css::uno::Reference< css::lang::XMultiServiceFactory > xSMGR = m_xSMGR; + aReadLock.unlock(); + // <- SYNCHRONIZED + + // check provider ... we know it's weak reference only + if ( ! xProvider.is()) + return; + + css::uno::Reference< css::util::XURLTransformer > xParser(xSMGR->createInstance(SERVICENAME_URLTRANSFORMER), css::uno::UNO_QUERY_THROW); + css::util::URL aCommand; + aCommand.Complete = sCommand; + xParser->parseStrict(aCommand); + + css::uno::Reference< css::frame::XDispatch > xDispatch = xProvider->queryDispatch(aCommand, SPECIALTARGET_SELF, 0); + if (xDispatch.is()) + xDispatch->dispatch(aCommand, css::uno::Sequence< css::beans::PropertyValue >()); + } + catch(const css::uno::Exception&) + {} +} + +} // namespace framework + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |