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 :
10 : #include <document.hxx>
11 : #include <clipcontext.hxx>
12 : #include <formulacell.hxx>
13 : #include <clipparam.hxx>
14 : #include <table.hxx>
15 : #include <tokenarray.hxx>
16 : #include <editutil.hxx>
17 : #include <listenercontext.hxx>
18 : #include <tokenstringcontext.hxx>
19 : #include <poolhelp.hxx>
20 : #include <bcaslot.hxx>
21 : #include <cellvalues.hxx>
22 :
23 : #include "dociter.hxx"
24 : #include "patattr.hxx"
25 : #include <svl/whiter.hxx>
26 : #include <editeng/colritem.hxx>
27 : #include "scitems.hxx"
28 :
29 : // Add totally brand-new methods to this source file.
30 :
31 6 : bool ScDocument::IsMerged( const ScAddress& rPos ) const
32 : {
33 6 : const ScTable* pTab = FetchTable(rPos.Tab());
34 6 : if (!pTab)
35 0 : return false;
36 :
37 6 : return pTab->IsMerged(rPos.Col(), rPos.Row());
38 : }
39 :
40 4 : void ScDocument::DeleteBeforeCopyFromClip( sc::CopyFromClipContext& rCxt, const ScMarkData& rMark )
41 : {
42 4 : SCTAB nClipTab = 0;
43 4 : const TableContainer& rClipTabs = rCxt.getClipDoc()->maTabs;
44 4 : SCTAB nClipTabCount = rClipTabs.size();
45 :
46 8 : for (SCTAB nTab = rCxt.getTabStart(); nTab <= rCxt.getTabEnd(); ++nTab)
47 : {
48 4 : ScTable* pTab = FetchTable(nTab);
49 4 : if (!pTab)
50 0 : continue;
51 :
52 4 : if (!rMark.GetTableSelect(nTab))
53 0 : continue;
54 :
55 8 : while (!rClipTabs[nClipTab])
56 0 : nClipTab = (nClipTab+1) % nClipTabCount;
57 :
58 4 : pTab->DeleteBeforeCopyFromClip(rCxt, *rClipTabs[nClipTab]);
59 :
60 4 : nClipTab = (nClipTab+1) % nClipTabCount;
61 : }
62 4 : }
63 :
64 138 : bool ScDocument::CopyOneCellFromClip(
65 : sc::CopyFromClipContext& rCxt, SCCOL nCol1, SCROW nRow1, SCCOL nCol2, SCROW nRow2 )
66 : {
67 138 : ScDocument* pClipDoc = rCxt.getClipDoc();
68 138 : if (pClipDoc->GetClipParam().mbCutMode)
69 : // We don't handle cut and paste or moving of cells here.
70 32 : return false;
71 :
72 106 : ScRange aClipRange = pClipDoc->GetClipParam().getWholeRange();
73 106 : if (aClipRange.aStart != aClipRange.aEnd)
74 : // The source is not really a single cell. Bail out.
75 100 : return false;
76 :
77 6 : ScAddress aSrcPos = aClipRange.aStart;
78 6 : if (pClipDoc->IsMerged(aSrcPos))
79 : // We don't handle merged source cell for this.
80 0 : return false;
81 :
82 6 : ScTable* pSrcTab = pClipDoc->FetchTable(aSrcPos.Tab());
83 6 : if (!pSrcTab)
84 0 : return false;
85 :
86 6 : ScCellValue& rSrcCell = rCxt.getSingleCell();
87 6 : const ScPatternAttr* pAttr = pClipDoc->GetPattern(aSrcPos);
88 6 : rCxt.setSingleCellPattern(pAttr);
89 6 : if (rCxt.isAsLink())
90 : {
91 : ScSingleRefData aRef;
92 0 : aRef.InitAddress(aSrcPos);
93 0 : aRef.SetFlag3D(true);
94 :
95 0 : ScTokenArray aArr;
96 0 : aArr.AddSingleReference(aRef);
97 0 : rSrcCell.set(new ScFormulaCell(pClipDoc, aSrcPos, aArr));
98 : }
99 : else
100 : {
101 6 : rSrcCell.set(pClipDoc->GetRefCellValue(aSrcPos));
102 :
103 : // Check the paste flag to see whether we want to paste this cell. If the
104 : // flag says we don't want to paste this cell, we'll return with true.
105 6 : InsertDeleteFlags nFlags = rCxt.getInsertFlag();
106 6 : bool bNumeric = (nFlags & IDF_VALUE) != IDF_NONE;
107 6 : bool bDateTime = (nFlags & IDF_DATETIME) != IDF_NONE;
108 6 : bool bString = (nFlags & IDF_STRING) != IDF_NONE;
109 6 : bool bBoolean = (nFlags & IDF_SPECIAL_BOOLEAN) != IDF_NONE;
110 6 : bool bFormula = (nFlags & IDF_FORMULA) != IDF_NONE;
111 :
112 6 : switch (rSrcCell.meType)
113 : {
114 : case CELLTYPE_VALUE:
115 : {
116 0 : bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric;
117 0 : if (!bPaste)
118 : // Don't paste this.
119 0 : rSrcCell.clear();
120 : }
121 0 : break;
122 : case CELLTYPE_STRING:
123 : case CELLTYPE_EDIT:
124 : {
125 2 : if (!bString)
126 : // Skip pasting.
127 0 : rSrcCell.clear();
128 : }
129 2 : break;
130 : case CELLTYPE_FORMULA:
131 : {
132 2 : if (bBoolean)
133 : {
134 : // Check if this formula cell is a boolean cell, and if so, go ahead and paste it.
135 0 : ScTokenArray* pCode = rSrcCell.mpFormula->GetCode();
136 0 : if (pCode && pCode->GetLen() == 1)
137 : {
138 0 : const formula::FormulaToken* p = pCode->First();
139 0 : if (p->GetOpCode() == ocTrue || p->GetOpCode() == ocFalse)
140 : // This is a boolean formula. Good.
141 0 : break;
142 : }
143 : }
144 :
145 2 : if (bFormula)
146 : // Good.
147 2 : break;
148 :
149 0 : sal_uInt16 nErr = rSrcCell.mpFormula->GetErrCode();
150 0 : if (nErr)
151 : {
152 : // error codes are cloned with values
153 0 : if (!bNumeric)
154 : // Error code is treated as numeric value. Don't paste it.
155 0 : rSrcCell.clear();
156 : }
157 0 : else if (rSrcCell.mpFormula->IsValue())
158 : {
159 0 : bool bPaste = rCxt.isDateCell(pSrcTab->aCol[aSrcPos.Col()], aSrcPos.Row()) ? bDateTime : bNumeric;
160 0 : if (!bPaste)
161 : {
162 : // Don't paste this.
163 0 : rSrcCell.clear();
164 0 : break;
165 : }
166 :
167 : // Turn this into a numeric cell.
168 0 : rSrcCell.set(rSrcCell.mpFormula->GetValue());
169 : }
170 0 : else if (bString)
171 : {
172 0 : svl::SharedString aStr = rSrcCell.mpFormula->GetString();
173 0 : if (aStr.isEmpty())
174 : {
175 : // do not clone empty string
176 0 : rSrcCell.clear();
177 0 : break;
178 : }
179 :
180 : // Turn this into a string or edit cell.
181 0 : if (rSrcCell.mpFormula->IsMultilineResult())
182 : {
183 : // TODO : Add shared string support to the edit engine to
184 : // make this process simpler.
185 0 : ScFieldEditEngine& rEngine = GetEditEngine();
186 0 : rEngine.SetText(rSrcCell.mpFormula->GetString().getString());
187 0 : boost::scoped_ptr<EditTextObject> pObj(rEngine.CreateTextObject());
188 0 : pObj->NormalizeString(GetSharedStringPool());
189 0 : rSrcCell.set(*pObj);
190 : }
191 : else
192 0 : rSrcCell.set(rSrcCell.mpFormula->GetString());
193 : }
194 : else
195 : // We don't want to paste this.
196 0 : rSrcCell.clear();
197 : }
198 0 : break;
199 : case CELLTYPE_NONE:
200 : default:
201 : // There is nothing to paste.
202 2 : rSrcCell.clear();
203 : }
204 : }
205 :
206 6 : if ((rCxt.getInsertFlag() & (IDF_NOTE | IDF_ADDNOTES)) != IDF_NONE)
207 6 : rCxt.setSingleCellNote(pClipDoc->GetNote(aSrcPos));
208 :
209 : // All good. Proceed with the pasting.
210 :
211 6 : SCTAB nTabEnd = rCxt.getTabEnd();
212 12 : for (SCTAB i = rCxt.getTabStart(); i <= nTabEnd && i < static_cast<SCTAB>(maTabs.size()); ++i)
213 : {
214 6 : maTabs[i]->CopyOneCellFromClip(rCxt, nCol1, nRow1, nCol2, nRow2);
215 6 : if (rCxt.getInsertFlag() & IDF_ATTRIB)
216 12 : maTabs[i]->CopyConditionalFormat(nCol1, nRow1, nCol2, nRow2, nCol1 - aClipRange.aStart.Col(),
217 18 : nRow1 - aClipRange.aStart.Row(), pSrcTab);
218 : }
219 :
220 6 : return true;
221 : }
222 :
223 0 : void ScDocument::SetValues( const ScAddress& rPos, const std::vector<double>& rVals )
224 : {
225 0 : ScTable* pTab = FetchTable(rPos.Tab());
226 0 : if (!pTab)
227 0 : return;
228 :
229 0 : pTab->SetValues(rPos.Col(), rPos.Row(), rVals);
230 : }
231 :
232 0 : void ScDocument::TransferCellValuesTo( const ScAddress& rTopPos, size_t nLen, sc::CellValues& rDest )
233 : {
234 0 : ScTable* pTab = FetchTable(rTopPos.Tab());
235 0 : if (!pTab)
236 0 : return;
237 :
238 0 : pTab->TransferCellValuesTo(rTopPos.Col(), rTopPos.Row(), nLen, rDest);
239 : }
240 :
241 0 : void ScDocument::CopyCellValuesFrom( const ScAddress& rTopPos, const sc::CellValues& rSrc )
242 : {
243 0 : ScTable* pTab = FetchTable(rTopPos.Tab());
244 0 : if (!pTab)
245 0 : return;
246 :
247 0 : pTab->CopyCellValuesFrom(rTopPos.Col(), rTopPos.Row(), rSrc);
248 : }
249 :
250 0 : std::vector<Color> ScDocument::GetDocColors()
251 : {
252 0 : std::vector<Color> docColors;
253 :
254 0 : for( unsigned int nTabIx = 0; nTabIx < maTabs.size(); ++nTabIx )
255 : {
256 0 : ScUsedAreaIterator aIt(this, nTabIx, 0, 0, MAXCOLCOUNT-1, MAXROWCOUNT-1);
257 :
258 0 : for( bool bIt = aIt.GetNext(); bIt; bIt = aIt.GetNext() )
259 : {
260 0 : const ScPatternAttr* pPattern = aIt.GetPattern();
261 :
262 0 : if( pPattern == 0 )
263 0 : continue;
264 :
265 0 : const SfxItemSet& rItemSet = pPattern->GetItemSet();
266 :
267 0 : SfxWhichIter aIter( rItemSet );
268 0 : sal_uInt16 nWhich = aIter.FirstWhich();
269 0 : while( nWhich )
270 : {
271 : const SfxPoolItem *pItem;
272 0 : if( SfxItemState::SET == rItemSet.GetItemState( nWhich, false, &pItem ) )
273 : {
274 0 : sal_uInt16 aWhich = pItem->Which();
275 0 : switch (aWhich)
276 : {
277 : // attributes we want to collect
278 : case ATTR_FONT_COLOR:
279 : case ATTR_BACKGROUND:
280 : {
281 0 : Color aColor( static_cast<const SvxColorItem*>(pItem)->GetValue() );
282 0 : if( COL_AUTO != aColor.GetColor() &&
283 0 : std::find(docColors.begin(), docColors.end(), aColor) == docColors.end() )
284 : {
285 0 : docColors.push_back( aColor );
286 : }
287 : }
288 0 : break;
289 : default:
290 0 : break;
291 : }
292 : }
293 :
294 0 : nWhich = aIter.NextWhich();
295 : }
296 0 : }
297 0 : }
298 0 : return docColors;
299 : }
300 :
301 980 : void ScDocument::SetCalcConfig( const ScCalcConfig& rConfig )
302 : {
303 980 : maCalcConfig = rConfig;
304 980 : }
305 :
306 4 : void ScDocument::ConvertFormulaToValue( const ScRange& rRange, sc::TableValues* pUndo )
307 : {
308 4 : sc::EndListeningContext aCxt(*this);
309 :
310 8 : for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
311 : {
312 4 : ScTable* pTab = FetchTable(nTab);
313 4 : if (!pTab)
314 0 : continue;
315 :
316 : pTab->ConvertFormulaToValue(
317 8 : aCxt, rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row(),
318 12 : pUndo);
319 : }
320 :
321 4 : aCxt.purgeEmptyBroadcasters();
322 4 : }
323 :
324 8 : void ScDocument::SwapNonEmpty( sc::TableValues& rValues )
325 : {
326 8 : const ScRange& rRange = rValues.getRange();
327 8 : if (!rRange.IsValid())
328 8 : return;
329 :
330 8 : boost::shared_ptr<sc::ColumnBlockPositionSet> pPosSet(new sc::ColumnBlockPositionSet(*this));
331 16 : sc::StartListeningContext aStartCxt(*this, pPosSet);
332 16 : sc::EndListeningContext aEndCxt(*this, pPosSet);
333 :
334 16 : for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
335 : {
336 8 : ScTable* pTab = FetchTable(nTab);
337 8 : if (!pTab)
338 0 : continue;
339 :
340 8 : pTab->SwapNonEmpty(rValues, aStartCxt, aEndCxt);
341 : }
342 :
343 16 : aEndCxt.purgeEmptyBroadcasters();
344 : }
345 :
346 64 : void ScDocument::PreprocessRangeNameUpdate()
347 : {
348 64 : sc::EndListeningContext aEndListenCxt(*this);
349 128 : sc::CompileFormulaContext aCompileCxt(this);
350 :
351 64 : TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
352 204 : for (; it != itEnd; ++it)
353 : {
354 140 : ScTable* p = *it;
355 140 : p->PreprocessRangeNameUpdate(aEndListenCxt, aCompileCxt);
356 64 : }
357 64 : }
358 :
359 18 : void ScDocument::PreprocessDBDataUpdate()
360 : {
361 18 : sc::EndListeningContext aEndListenCxt(*this);
362 36 : sc::CompileFormulaContext aCompileCxt(this);
363 :
364 18 : TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
365 40 : for (; it != itEnd; ++it)
366 : {
367 22 : ScTable* p = *it;
368 22 : p->PreprocessDBDataUpdate(aEndListenCxt, aCompileCxt);
369 18 : }
370 18 : }
371 :
372 82 : void ScDocument::CompileHybridFormula()
373 : {
374 82 : sc::StartListeningContext aStartListenCxt(*this);
375 164 : sc::CompileFormulaContext aCompileCxt(this);
376 82 : TableContainer::iterator it = maTabs.begin(), itEnd = maTabs.end();
377 244 : for (; it != itEnd; ++it)
378 : {
379 162 : ScTable* p = *it;
380 162 : p->CompileHybridFormula(aStartListenCxt, aCompileCxt);
381 82 : }
382 82 : }
383 :
384 1994 : void ScDocument::SharePooledResources( ScDocument* pSrcDoc )
385 : {
386 1994 : xPoolHelper = pSrcDoc->xPoolHelper;
387 1994 : mpCellStringPool = pSrcDoc->mpCellStringPool;
388 1994 : }
389 :
390 1154 : void ScDocument::UpdateScriptTypes( const ScAddress& rPos, SCCOL nColSize, SCROW nRowSize )
391 : {
392 1154 : ScTable* pTab = FetchTable(rPos.Tab());
393 1154 : if (!pTab)
394 1154 : return;
395 :
396 1154 : pTab->UpdateScriptTypes(rPos.Col(), rPos.Row(), rPos.Col()+nColSize-1, rPos.Row()+nRowSize-1);
397 : }
398 :
399 46 : bool ScDocument::HasUniformRowHeight( SCTAB nTab, SCROW nRow1, SCROW nRow2 ) const
400 : {
401 46 : const ScTable* pTab = FetchTable(nTab);
402 46 : if (!pTab)
403 0 : return false;
404 :
405 46 : return pTab->HasUniformRowHeight(nRow1, nRow2);
406 : }
407 :
408 10 : void ScDocument::UnshareFormulaCells( SCTAB nTab, SCCOL nCol, std::vector<SCROW>& rRows )
409 : {
410 10 : ScTable* pTab = FetchTable(nTab);
411 10 : if (!pTab)
412 10 : return;
413 :
414 10 : pTab->UnshareFormulaCells(nCol, rRows);
415 : }
416 :
417 10 : void ScDocument::RegroupFormulaCells( SCTAB nTab, SCCOL nCol )
418 : {
419 10 : ScTable* pTab = FetchTable(nTab);
420 10 : if (!pTab)
421 10 : return;
422 :
423 10 : pTab->RegroupFormulaCells(nCol);
424 : }
425 :
426 12 : void ScDocument::CollectAllAreaListeners(
427 : std::vector<SvtListener*>& rListener, const ScRange& rRange, sc::AreaOverlapType eType )
428 : {
429 12 : if (!pBASM)
430 12 : return;
431 :
432 12 : std::vector<sc::AreaListener> aAL = pBASM->GetAllListeners(rRange, eType);
433 12 : std::vector<sc::AreaListener>::iterator it = aAL.begin(), itEnd = aAL.end();
434 14 : for (; it != itEnd; ++it)
435 14 : rListener.push_back(it->mpListener);
436 : }
437 :
438 0 : bool ScDocument::HasFormulaCell( const ScRange& rRange ) const
439 : {
440 0 : if (!rRange.IsValid())
441 0 : return false;
442 :
443 0 : for (SCTAB nTab = rRange.aStart.Tab(); nTab <= rRange.aEnd.Tab(); ++nTab)
444 : {
445 0 : const ScTable* pTab = FetchTable(nTab);
446 0 : if (!pTab)
447 0 : continue;
448 :
449 0 : if (pTab->HasFormulaCell(rRange.aStart.Col(), rRange.aStart.Row(), rRange.aEnd.Col(), rRange.aEnd.Row()))
450 0 : return true;
451 : }
452 :
453 0 : return false;
454 228 : }
455 :
456 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|