Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
5 : * This Source Code Form is subject to the terms of the Mozilla Public
6 : * License, v. 2.0. If a copy of the MPL was not distributed with this
7 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
11 : * Licensed to the Apache Software Foundation (ASF) under one or more
12 : * contributor license agreements. See the NOTICE file distributed
13 : * with this work for additional information regarding copyright
14 : * ownership. The ASF licenses this file to you under the Apache
15 : * License, Version 2.0 (the "License"); you may not use this file
16 : * except in compliance with the License. You may obtain a copy of
17 : * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 : */
19 :
20 : #include "macromgr.hxx"
21 : #include "document.hxx"
22 :
23 : #include "basic/basmgr.hxx"
24 : #include "cppuhelper/implbase1.hxx"
25 : #include "sfx2/objsh.hxx"
26 : #include "formulacell.hxx"
27 : #include <com/sun/star/container/XContainer.hpp>
28 :
29 : #include <list>
30 :
31 : using namespace ::com::sun::star;
32 : using ::com::sun::star::uno::RuntimeException;
33 : using ::com::sun::star::uno::Reference;
34 : using ::boost::unordered_map;
35 : using ::std::list;
36 : using ::std::for_each;
37 : using ::std::pair;
38 :
39 : // ============================================================================
40 :
41 : /**
42 : * A simple container to keep track of cells that depend on basic modules
43 : * changes. We don't check for duplicates at insertion time; instead, we
44 : * remove duplicates at query time.
45 : */
46 2 : class ScUserMacroDepTracker
47 : {
48 : public:
49 0 : void addCell(const OUString& rModuleName, ScFormulaCell* pCell)
50 : {
51 0 : ModuleCellMap::iterator itr = maCells.find(rModuleName);
52 0 : if (itr == maCells.end())
53 : {
54 : pair<ModuleCellMap::iterator, bool> r = maCells.insert(
55 0 : ModuleCellMap::value_type(rModuleName, list<ScFormulaCell*>()));
56 :
57 0 : if (!r.second)
58 : // insertion failed.
59 0 : return;
60 :
61 0 : itr = r.first;
62 : }
63 0 : itr->second.push_back(pCell);
64 : }
65 :
66 1 : void removeCell(ScFormulaCell* pCell)
67 : {
68 1 : ModuleCellMap::iterator itr = maCells.begin(), itrEnd = maCells.end();
69 1 : for (; itr != itrEnd; ++itr)
70 0 : itr->second.remove(pCell);
71 1 : }
72 :
73 0 : void getCellsByModule(const OUString& rModuleName, list<ScFormulaCell*>& rCells)
74 : {
75 0 : ModuleCellMap::iterator itr = maCells.find(rModuleName);
76 0 : if (itr == maCells.end())
77 0 : return;
78 :
79 0 : list<ScFormulaCell*>& rCellList = itr->second;
80 :
81 : // Remove duplicates.
82 0 : rCellList.sort();
83 0 : rCellList.unique();
84 : // exception safe copy
85 0 : list<ScFormulaCell*> temp(rCellList);
86 0 : rCells.swap(temp);
87 : }
88 :
89 : private:
90 : typedef boost::unordered_map<OUString, list<ScFormulaCell*>, OUStringHash> ModuleCellMap;
91 : ModuleCellMap maCells;
92 : };
93 :
94 :
95 : // ============================================================================
96 :
97 1 : ScMacroManager::ScMacroManager(ScDocument* pDoc) :
98 1 : mpDepTracker(new ScUserMacroDepTracker),
99 2 : mpDoc(pDoc)
100 : {
101 1 : }
102 :
103 1 : ScMacroManager::~ScMacroManager()
104 : {
105 1 : }
106 :
107 : typedef ::cppu::WeakImplHelper1< ::com::sun::star::container::XContainerListener > ContainerListenerHelper;
108 :
109 0 : class VBAProjectListener : public ContainerListenerHelper
110 : {
111 : ScMacroManager* mpMacroMgr;
112 : public:
113 0 : VBAProjectListener( ScMacroManager* pMacroMgr ) : mpMacroMgr( pMacroMgr ) {}
114 : // XEventListener
115 0 : virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw(RuntimeException) {}
116 :
117 : // XContainerListener
118 0 : virtual void SAL_CALL elementInserted( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException){}
119 0 : virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) throw(RuntimeException)
120 : {
121 0 : OUString sModuleName;
122 0 : Event.Accessor >>= sModuleName;
123 : OSL_TRACE("VBAProjectListener::elementReplaced(%s)", OUStringToOString( sModuleName, RTL_TEXTENCODING_UTF8 ).getStr() );
124 0 : mpMacroMgr->InitUserFuncData();
125 0 : mpMacroMgr->BroadcastModuleUpdate(sModuleName);
126 0 : }
127 0 : virtual void SAL_CALL elementRemoved( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException){}
128 :
129 : };
130 :
131 0 : void ScMacroManager::InitUserFuncData()
132 : {
133 : // Clear boost::unordered_map
134 0 : mhFuncToVolatile.clear();
135 0 : OUString sProjectName("Standard");
136 :
137 0 : Reference< container::XContainer > xModuleContainer;
138 0 : SfxObjectShell* pShell = mpDoc->GetDocumentShell();
139 0 : if (pShell && !pShell->GetBasicManager()->GetName().isEmpty())
140 : {
141 0 : sProjectName = pShell->GetBasicManager()->GetName();
142 : }
143 : try
144 : {
145 0 : Reference< script::XLibraryContainer > xLibraries( pShell->GetBasicContainer(), uno::UNO_QUERY_THROW );
146 0 : xModuleContainer.set( xLibraries->getByName( sProjectName ), uno::UNO_QUERY_THROW );
147 :
148 0 : if ( xModuleContainer.is() )
149 : {
150 : // remove old listener ( if there was one )
151 0 : if ( mxContainerListener.is() )
152 0 : xModuleContainer->removeContainerListener( mxContainerListener );
153 : // Create listener
154 0 : mxContainerListener = new VBAProjectListener( this );
155 0 : xModuleContainer->addContainerListener( mxContainerListener );
156 0 : }
157 : }
158 0 : catch( uno::Exception& )
159 : {
160 0 : }
161 0 : }
162 :
163 0 : void ScMacroManager::SetUserFuncVolatile( const OUString& sName, bool isVolatile )
164 : {
165 0 : mhFuncToVolatile[ sName ] = isVolatile;
166 0 : }
167 :
168 0 : bool ScMacroManager::GetUserFuncVolatile( const OUString& sName )
169 : {
170 0 : NameBoolMap::iterator it = mhFuncToVolatile.find( sName );
171 0 : if ( it == mhFuncToVolatile.end() )
172 0 : return false;
173 0 : return it->second;
174 : }
175 :
176 0 : void ScMacroManager::AddDependentCell(const OUString& aModuleName, ScFormulaCell* pCell)
177 : {
178 0 : mpDepTracker->addCell(aModuleName, pCell);
179 0 : }
180 :
181 1 : void ScMacroManager::RemoveDependentCell(ScFormulaCell* pCell)
182 : {
183 1 : mpDepTracker->removeCell(pCell);
184 1 : }
185 :
186 0 : void ScMacroManager::BroadcastModuleUpdate(const OUString& aModuleName)
187 : {
188 0 : list<ScFormulaCell*> aCells;
189 0 : mpDepTracker->getCellsByModule(aModuleName, aCells);
190 0 : list<ScFormulaCell*>::iterator itr = aCells.begin(), itrEnd = aCells.end();
191 0 : for (; itr != itrEnd; ++itr)
192 : {
193 0 : ScFormulaCell* pCell = *itr;
194 0 : mpDoc->PutInFormulaTree(pCell); // for F9 recalc
195 :
196 : // for recalc on cell value change. If the cell is not volatile, the
197 : // cell stops listening right away after it gets re-interpreted.
198 0 : mpDoc->StartListeningArea(BCA_LISTEN_ALWAYS, pCell);
199 0 : }
200 93 : }
201 :
202 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|