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