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 "cell.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 ::rtl::OUString;
35 : using ::rtl::OUStringHash;
36 : using ::boost::unordered_map;
37 : using ::std::list;
38 : using ::std::for_each;
39 : using ::std::pair;
40 :
41 : // ============================================================================
42 :
43 : /**
44 : * A simple container to keep track of cells that depend on basic modules
45 : * changes. We don't check for duplicates at insertion time; instead, we
46 : * remove duplicates at query time.
47 : */
48 2 : class ScUserMacroDepTracker
49 : {
50 : public:
51 0 : void addCell(const OUString& rModuleName, ScFormulaCell* pCell)
52 : {
53 0 : ModuleCellMap::iterator itr = maCells.find(rModuleName);
54 0 : if (itr == maCells.end())
55 : {
56 : pair<ModuleCellMap::iterator, bool> r = maCells.insert(
57 0 : ModuleCellMap::value_type(rModuleName, list<ScFormulaCell*>()));
58 :
59 0 : if (!r.second)
60 : // insertion failed.
61 0 : return;
62 :
63 0 : itr = r.first;
64 : }
65 0 : itr->second.push_back(pCell);
66 : }
67 :
68 1 : void removeCell(ScFormulaCell* pCell)
69 : {
70 1 : ModuleCellMap::iterator itr = maCells.begin(), itrEnd = maCells.end();
71 1 : for (; itr != itrEnd; ++itr)
72 0 : itr->second.remove(pCell);
73 1 : }
74 :
75 0 : void getCellsByModule(const OUString& rModuleName, list<ScFormulaCell*>& rCells)
76 : {
77 0 : ModuleCellMap::iterator itr = maCells.find(rModuleName);
78 0 : if (itr == maCells.end())
79 0 : return;
80 :
81 0 : list<ScFormulaCell*>& rCellList = itr->second;
82 :
83 : // Remove duplicates.
84 0 : rCellList.sort();
85 0 : rCellList.unique();
86 : // exception safe copy
87 0 : list<ScFormulaCell*> temp(rCellList);
88 0 : rCells.swap(temp);
89 : }
90 :
91 : private:
92 : typedef boost::unordered_map<OUString, list<ScFormulaCell*>, OUStringHash> ModuleCellMap;
93 : ModuleCellMap maCells;
94 : };
95 :
96 :
97 : // ============================================================================
98 :
99 1 : ScMacroManager::ScMacroManager(ScDocument* pDoc) :
100 1 : mpDepTracker(new ScUserMacroDepTracker),
101 2 : mpDoc(pDoc)
102 : {
103 1 : }
104 :
105 1 : ScMacroManager::~ScMacroManager()
106 : {
107 1 : }
108 :
109 : typedef ::cppu::WeakImplHelper1< ::com::sun::star::container::XContainerListener > ContainerListenerHelper;
110 :
111 0 : class VBAProjectListener : public ContainerListenerHelper
112 : {
113 : ScMacroManager* mpMacroMgr;
114 : public:
115 0 : VBAProjectListener( ScMacroManager* pMacroMgr ) : mpMacroMgr( pMacroMgr ) {}
116 : // XEventListener
117 0 : virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw(RuntimeException) {}
118 :
119 : // XContainerListener
120 0 : virtual void SAL_CALL elementInserted( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException){}
121 0 : virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) throw(RuntimeException)
122 : {
123 0 : rtl::OUString sModuleName;
124 0 : Event.Accessor >>= sModuleName;
125 : OSL_TRACE("VBAProjectListener::elementReplaced(%s)", rtl::OUStringToOString( sModuleName, RTL_TEXTENCODING_UTF8 ).getStr() );
126 0 : mpMacroMgr->InitUserFuncData();
127 0 : mpMacroMgr->BroadcastModuleUpdate(sModuleName);
128 0 : }
129 0 : virtual void SAL_CALL elementRemoved( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException){}
130 :
131 : };
132 :
133 0 : void ScMacroManager::InitUserFuncData()
134 : {
135 : // Clear boost::unordered_map
136 0 : mhFuncToVolatile.clear();
137 0 : OUString sProjectName("Standard");
138 :
139 0 : Reference< container::XContainer > xModuleContainer;
140 0 : SfxObjectShell* pShell = mpDoc->GetDocumentShell();
141 0 : if (pShell && !pShell->GetBasicManager()->GetName().isEmpty())
142 : {
143 0 : sProjectName = pShell->GetBasicManager()->GetName();
144 : }
145 : try
146 : {
147 0 : Reference< script::XLibraryContainer > xLibraries( pShell->GetBasicContainer(), uno::UNO_QUERY_THROW );
148 0 : xModuleContainer.set( xLibraries->getByName( sProjectName ), uno::UNO_QUERY_THROW );
149 :
150 0 : if ( xModuleContainer.is() )
151 : {
152 : // remove old listener ( if there was one )
153 0 : if ( mxContainerListener.is() )
154 0 : xModuleContainer->removeContainerListener( mxContainerListener );
155 : // Create listener
156 0 : mxContainerListener = new VBAProjectListener( this );
157 0 : xModuleContainer->addContainerListener( mxContainerListener );
158 0 : }
159 : }
160 0 : catch( uno::Exception& )
161 : {
162 0 : }
163 0 : }
164 :
165 0 : void ScMacroManager::SetUserFuncVolatile( const OUString& sName, bool isVolatile )
166 : {
167 0 : mhFuncToVolatile[ sName ] = isVolatile;
168 0 : }
169 :
170 0 : bool ScMacroManager::GetUserFuncVolatile( const OUString& sName )
171 : {
172 0 : NameBoolMap::iterator it = mhFuncToVolatile.find( sName );
173 0 : if ( it == mhFuncToVolatile.end() )
174 0 : return false;
175 0 : return it->second;
176 : }
177 :
178 0 : void ScMacroManager::AddDependentCell(const OUString& aModuleName, ScFormulaCell* pCell)
179 : {
180 0 : mpDepTracker->addCell(aModuleName, pCell);
181 0 : }
182 :
183 1 : void ScMacroManager::RemoveDependentCell(ScFormulaCell* pCell)
184 : {
185 1 : mpDepTracker->removeCell(pCell);
186 1 : }
187 :
188 0 : void ScMacroManager::BroadcastModuleUpdate(const OUString& aModuleName)
189 : {
190 0 : list<ScFormulaCell*> aCells;
191 0 : mpDepTracker->getCellsByModule(aModuleName, aCells);
192 0 : list<ScFormulaCell*>::iterator itr = aCells.begin(), itrEnd = aCells.end();
193 0 : for (; itr != itrEnd; ++itr)
194 : {
195 0 : ScFormulaCell* pCell = *itr;
196 0 : mpDoc->PutInFormulaTree(pCell); // for F9 recalc
197 :
198 : // for recalc on cell value change. If the cell is not volatile, the
199 : // cell stops listening right away after it gets re-interpreted.
200 0 : mpDoc->StartListeningArea(BCA_LISTEN_ALWAYS, pCell);
201 0 : }
202 0 : }
203 :
204 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|