diff options
Diffstat (limited to 'sd/source/ui/toolpanel/TaskPaneFocusManager.cxx')
-rw-r--r-- | sd/source/ui/toolpanel/TaskPaneFocusManager.cxx | 325 |
1 files changed, 325 insertions, 0 deletions
diff --git a/sd/source/ui/toolpanel/TaskPaneFocusManager.cxx b/sd/source/ui/toolpanel/TaskPaneFocusManager.cxx new file mode 100644 index 000000000000..48882d0f2f9e --- /dev/null +++ b/sd/source/ui/toolpanel/TaskPaneFocusManager.cxx @@ -0,0 +1,325 @@ +/************************************************************************* + * + * 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_sd.hxx" + +#include "TaskPaneFocusManager.hxx" + +#include <vcl/window.hxx> +#include <vos/mutex.hxx> +#include <vcl/svapp.hxx> +#include <vcl/event.hxx> +#include <hash_map> + +namespace { + +class WindowHash +{ +public: + size_t operator()(const ::Window* argument) const + { return reinterpret_cast<unsigned long>(argument); } +}; + +class EventDescriptor +{ +public: + EventDescriptor (const KeyCode& rKey, ::Window* pWindow) + : maKeyCode(rKey), mpTargetWindow(pWindow) {} + KeyCode maKeyCode; + ::Window* mpTargetWindow; +}; + +} // end of anonymous namespace + + + + +namespace sd { namespace toolpanel { + + + +class FocusManager::LinkMap + : public ::std::hash_multimap< ::Window*, EventDescriptor, WindowHash> +{ +}; + + + +FocusManager* FocusManager::spInstance = NULL; + + +FocusManager& FocusManager::Instance (void) +{ + if (spInstance == NULL) + { + ::vos::OGuard aGuard (::Application::GetSolarMutex()); + if (spInstance == NULL) + spInstance = new FocusManager (); + } + return *spInstance; +} + + + + +FocusManager::FocusManager (void) + : mpLinks(new LinkMap()) +{ +} + + + + +FocusManager::~FocusManager (void) +{ + Clear(); +} + + + + +void FocusManager::Clear (void) +{ + if (mpLinks.get() != NULL) + { + while ( ! mpLinks->empty()) + { + ::Window* pWindow = mpLinks->begin()->first; + if (pWindow == NULL) + { + mpLinks->erase(mpLinks->begin()); + } + else + { + RemoveLinks(pWindow); + } + } + } +} + + + + +void FocusManager::RegisterUpLink (::Window* pSource, ::Window* pTarget) +{ + RegisterLink(pSource, pTarget, KEY_ESCAPE); +} + + + + +void FocusManager::RegisterDownLink (::Window* pSource, ::Window* pTarget) +{ + RegisterLink(pSource, pTarget, KEY_RETURN); +} + + + + +void FocusManager::RegisterLink ( + ::Window* pSource, + ::Window* pTarget, + const KeyCode& rKey) +{ + OSL_ASSERT(pSource!=NULL); + OSL_ASSERT(pTarget!=NULL); + + if (pSource==NULL || pTarget==NULL) + return; + + // Register this focus manager as event listener at the source window. + if (mpLinks->equal_range(pSource).first == mpLinks->end()) + pSource->AddEventListener (LINK (this, FocusManager, WindowEventListener)); + mpLinks->insert(LinkMap::value_type(pSource, EventDescriptor(rKey,pTarget))); +} + + + + +void FocusManager::RemoveLinks ( + ::Window* pSourceWindow, + ::Window* pTargetWindow) +{ + OSL_ASSERT(pSourceWindow!=NULL); + OSL_ASSERT(pTargetWindow!=NULL); + + if (pSourceWindow==NULL || pTargetWindow==NULL) + { + // This method was called with invalid arguments. To avoid + // referencing windows that will soon be deleted we clear *all* + // links as an emergency fallback. + Clear(); + return; + } + + ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates; + LinkMap::iterator iCandidate; + bool bLoop (mpLinks->size() > 0); + while (bLoop) + { + aCandidates = mpLinks->equal_range(pSourceWindow); + if (aCandidates.first == mpLinks->end()) + { + // No links for the source window found -> nothing more to do. + bLoop = false; + } + else + { + // Set the loop control to false so that when no candidate for + // deletion is found the loop is left. + bLoop = false; + for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate) + if (iCandidate->second.mpTargetWindow == pTargetWindow) + { + mpLinks->erase(iCandidate); + // One link erased. The iterators have become invalid so + // start the search for links to delete anew. + bLoop = true; + break; + } + } + } + + RemoveUnusedEventListener(pSourceWindow); +} + + + + +void FocusManager::RemoveLinks (::Window* pWindow) +{ + OSL_ASSERT(pWindow!=NULL); + + if (pWindow == NULL) + { + // This method was called with invalid arguments. To avoid + // referencing windows that will soon be deleted we clear *all* + // links as an emergency fallback. + Clear(); + return; + } + + // Make sure that we are not called back for the window. + pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener)); + + // Remove the links from the given window. + ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates(mpLinks->equal_range(pWindow)); + mpLinks->erase(aCandidates.first, aCandidates.second); + + // Remove links to the given window. + bool bLinkRemoved; + do + { + bLinkRemoved = false; + LinkMap::iterator iLink; + for (iLink=mpLinks->begin(); iLink!=mpLinks->end(); ++iLink) + { + if (iLink->second.mpTargetWindow == pWindow) + { + RemoveUnusedEventListener(iLink->first); + mpLinks->erase(iLink); + bLinkRemoved = true; + break; + } + } + } + while (bLinkRemoved); +} + + + + +void FocusManager::RemoveUnusedEventListener (::Window* pWindow) +{ + OSL_ASSERT(pWindow!=NULL); + + if (pWindow == NULL) + return; + + // When there are no more links from the window to another window + // then remove the event listener from the window. + if (mpLinks->find(pWindow) == mpLinks->end()) + pWindow->RemoveEventListener (LINK (this, FocusManager, WindowEventListener)); +} + + + + +bool FocusManager::TransferFocus ( + ::Window* pSourceWindow, + const KeyCode& rKeyCode) +{ + bool bSuccess (false); + + OSL_ASSERT(pSourceWindow!=NULL); + if (pSourceWindow == NULL) + return bSuccess; + + ::std::pair<LinkMap::iterator,LinkMap::iterator> aCandidates ( + mpLinks->equal_range(pSourceWindow)); + LinkMap::const_iterator iCandidate; + for (iCandidate=aCandidates.first; iCandidate!=aCandidates.second; ++iCandidate) + if (iCandidate->second.maKeyCode == rKeyCode) + { + OSL_ASSERT(iCandidate->second.mpTargetWindow != NULL); + iCandidate->second.mpTargetWindow->GrabFocus(); + bSuccess = true; + break; + } + + return bSuccess; +} + + + + +IMPL_LINK(FocusManager, WindowEventListener, VclSimpleEvent*, pEvent) +{ + if (pEvent!=NULL && pEvent->ISA(VclWindowEvent)) + { + VclWindowEvent* pWindowEvent = static_cast<VclWindowEvent*>(pEvent); + switch (pWindowEvent->GetId()) + { + case VCLEVENT_WINDOW_KEYINPUT: + { + ::Window* pSource = pWindowEvent->GetWindow(); + KeyEvent* pKeyEvent = static_cast<KeyEvent*>(pWindowEvent->GetData()); + TransferFocus(pSource, pKeyEvent->GetKeyCode()); + } + break; + + case VCLEVENT_OBJECT_DYING: + RemoveLinks(pWindowEvent->GetWindow()); + break; + } + } + return 1; +} + + +} } // end of namespace ::sd::toolpanel |