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 <osl/diagnose.h>
26 : #include <sfx2/objsh.hxx>
27 : #include "formulacell.hxx"
28 : #include <com/sun/star/container/XContainer.hpp>
29 :
30 : #include <list>
31 :
32 : using namespace ::com::sun::star;
33 : using ::com::sun::star::uno::RuntimeException;
34 : using ::com::sun::star::uno::Reference;
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 4 : 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 2 : void removeCell(ScFormulaCell* pCell)
65 : {
66 2 : ModuleCellMap::iterator itr = maCells.begin(), itrEnd = maCells.end();
67 2 : for (; itr != itrEnd; ++itr)
68 0 : itr->second.remove(pCell);
69 2 : }
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 std::unordered_map<OUString, list<ScFormulaCell*>, OUStringHash> ModuleCellMap;
89 : ModuleCellMap maCells;
90 : };
91 :
92 2 : ScMacroManager::ScMacroManager(ScDocument* pDoc) :
93 2 : mpDepTracker(new ScUserMacroDepTracker),
94 4 : mpDoc(pDoc)
95 : {
96 2 : }
97 :
98 2 : ScMacroManager::~ScMacroManager()
99 : {
100 2 : }
101 :
102 : typedef ::cppu::WeakImplHelper1< ::com::sun::star::container::XContainerListener > ContainerListenerHelper;
103 :
104 0 : class VBAProjectListener : public ContainerListenerHelper
105 : {
106 : ScMacroManager* mpMacroMgr;
107 : public:
108 0 : VBAProjectListener( ScMacroManager* pMacroMgr ) : mpMacroMgr( pMacroMgr ) {}
109 : // XEventListener
110 0 : virtual void SAL_CALL disposing( const lang::EventObject& /*Source*/ ) throw(RuntimeException, std::exception) SAL_OVERRIDE {}
111 :
112 : // XContainerListener
113 0 : virtual void SAL_CALL elementInserted( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException, std::exception) SAL_OVERRIDE {}
114 0 : virtual void SAL_CALL elementReplaced( const container::ContainerEvent& Event ) throw(RuntimeException, std::exception) SAL_OVERRIDE
115 : {
116 0 : OUString sModuleName;
117 0 : Event.Accessor >>= sModuleName;
118 : OSL_TRACE("VBAProjectListener::elementReplaced(%s)", OUStringToOString( sModuleName, RTL_TEXTENCODING_UTF8 ).getStr() );
119 0 : mpMacroMgr->InitUserFuncData();
120 0 : mpMacroMgr->BroadcastModuleUpdate(sModuleName);
121 0 : }
122 0 : virtual void SAL_CALL elementRemoved( const container::ContainerEvent& /*Event*/ ) throw(RuntimeException, std::exception) SAL_OVERRIDE {}
123 :
124 : };
125 :
126 0 : void ScMacroManager::InitUserFuncData()
127 : {
128 : // Clear unordered_map
129 0 : mhFuncToVolatile.clear();
130 0 : OUString sProjectName("Standard");
131 :
132 0 : Reference< container::XContainer > xModuleContainer;
133 0 : SfxObjectShell* pShell = mpDoc->GetDocumentShell();
134 0 : if (!pShell)
135 0 : return;
136 0 : if (!pShell->GetBasicManager()->GetName().isEmpty())
137 : {
138 0 : sProjectName = pShell->GetBasicManager()->GetName();
139 : }
140 : try
141 : {
142 0 : Reference< script::XLibraryContainer > xLibraries( pShell->GetBasicContainer(), uno::UNO_QUERY_THROW );
143 0 : xModuleContainer.set( xLibraries->getByName( sProjectName ), uno::UNO_QUERY_THROW );
144 :
145 0 : if ( xModuleContainer.is() )
146 : {
147 : // remove old listener ( if there was one )
148 0 : if ( mxContainerListener.is() )
149 0 : xModuleContainer->removeContainerListener( mxContainerListener );
150 : // Create listener
151 0 : mxContainerListener = new VBAProjectListener( this );
152 0 : xModuleContainer->addContainerListener( mxContainerListener );
153 0 : }
154 : }
155 0 : catch (const uno::Exception&)
156 : {
157 0 : }
158 : }
159 :
160 0 : void ScMacroManager::SetUserFuncVolatile( const OUString& sName, bool isVolatile )
161 : {
162 0 : mhFuncToVolatile[ sName ] = isVolatile;
163 0 : }
164 :
165 0 : bool ScMacroManager::GetUserFuncVolatile( const OUString& sName )
166 : {
167 0 : NameBoolMap::iterator it = mhFuncToVolatile.find( sName );
168 0 : if ( it == mhFuncToVolatile.end() )
169 0 : return false;
170 0 : return it->second;
171 : }
172 :
173 0 : void ScMacroManager::AddDependentCell(const OUString& aModuleName, ScFormulaCell* pCell)
174 : {
175 0 : mpDepTracker->addCell(aModuleName, pCell);
176 0 : }
177 :
178 2 : void ScMacroManager::RemoveDependentCell(ScFormulaCell* pCell)
179 : {
180 2 : mpDepTracker->removeCell(pCell);
181 2 : }
182 :
183 0 : void ScMacroManager::BroadcastModuleUpdate(const OUString& aModuleName)
184 : {
185 0 : list<ScFormulaCell*> aCells;
186 0 : mpDepTracker->getCellsByModule(aModuleName, aCells);
187 0 : list<ScFormulaCell*>::iterator itr = aCells.begin(), itrEnd = aCells.end();
188 0 : for (; itr != itrEnd; ++itr)
189 : {
190 0 : ScFormulaCell* pCell = *itr;
191 0 : mpDoc->PutInFormulaTree(pCell); // for F9 recalc
192 :
193 : // for recalc on cell value change. If the cell is not volatile, the
194 : // cell stops listening right away after it gets re-interpreted.
195 0 : mpDoc->StartListeningArea(BCA_LISTEN_ALWAYS, false, pCell);
196 0 : }
197 156 : }
198 :
199 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|