1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <scitems.hxx>
22 #include <svx/pageitem.hxx>
23 #include <sfx2/linkmgr.hxx>
27 #include <stlpool.hxx>
29 #include <viewdata.hxx>
30 #include <tabvwsh.hxx>
31 #include <tablink.hxx>
32 #include <globstr.hrc>
33 #include <scresid.hxx>
35 #include <compiler.hxx>
36 #include <interpre.hxx>
37 #include <formulaopt.hxx>
39 #include <vcl/svapp.hxx>
40 #include <vcl/weld.hxx>
49 SfxStyleSheetBase
*pSource
;
50 SfxStyleSheetBase
*pDest
;
57 void ScDocShell::SetVisArea( const tools::Rectangle
& rVisArea
)
59 // with the SnapVisArea call in SetVisAreaOrSize, it's safe to always
60 // use both the size and position of the VisArea
61 SetVisAreaOrSize( rVisArea
);
64 static void lcl_SetTopRight( tools::Rectangle
& rRect
, const Point
& rPos
)
66 Size aSize
= rRect
.GetSize();
67 rRect
.SetRight( rPos
.X() );
68 rRect
.SetLeft( rPos
.X() - aSize
.Width() + 1 );
69 rRect
.SetTop( rPos
.Y() );
70 rRect
.SetBottom( rPos
.Y() + aSize
.Height() - 1 );
73 void ScDocShell::SetVisAreaOrSize( const tools::Rectangle
& rVisArea
)
75 bool bNegativePage
= m_pDocument
->IsNegativePage( m_pDocument
->GetVisibleTab() );
77 tools::Rectangle aArea
= rVisArea
;
78 // when loading, don't check for negative values, because the sheet orientation
80 if ( !m_pDocument
->IsImportingXML() )
82 if ( ( bNegativePage
? (aArea
.Right() > 0) : (aArea
.Left() < 0) ) || aArea
.Top() < 0 )
84 // VisArea start position can't be negative.
85 // Move the VisArea, otherwise only the upper left position would
86 // be changed in SnapVisArea, and the size would be wrong.
88 Point
aNewPos( 0, std::max( aArea
.Top(), tools::Long(0) ) );
91 aNewPos
.setX( std::min( aArea
.Right(), tools::Long(0) ) );
92 lcl_SetTopRight( aArea
, aNewPos
);
96 aNewPos
.setX( std::max( aArea
.Left(), tools::Long(0) ) );
97 aArea
.SetPos( aNewPos
);
102 // adjust position here!
104 // when loading an ole object, the VisArea is set from the document's
105 // view settings and must be used as-is (document content may not be complete yet).
106 if ( !m_pDocument
->IsImportingXML() )
107 SnapVisArea( aArea
);
109 //TODO/LATER: it's unclear which IPEnv is used here
111 SvInPlaceEnvironment* pEnv = GetIPEnv();
114 vcl::Window* pWin = pEnv->GetEditWin();
115 pEnv->MakeScale( aArea.GetSize(), MapUnit::Map100thMM,
116 pWin->LogicToPixel( aArea.GetSize() ) );
119 //TODO/LATER: formerly in SvInplaceObject
120 SfxObjectShell::SetVisArea( aArea
);
122 if (m_bIsInplace
) // adjust zoom in the InPlace View
124 ScTabViewShell
* pViewSh
= ScTabViewShell::GetActiveViewShell();
127 if (pViewSh
->GetViewData().GetDocShell() == this)
128 pViewSh
->UpdateOleZoom();
132 if (!m_pDocument
->IsEmbedded())
136 m_pDocument
->GetEmbedded( aOld
);
137 m_pDocument
->SetEmbedded( m_pDocument
->GetVisibleTab(), aArea
);
139 m_pDocument
->GetEmbedded( aNew
);
141 PostPaint(0,0,0,m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),MAXTAB
,PaintPartFlags::Grid
);
143 //TODO/LATER: currently not implemented
144 //ViewChanged( ASPECT_CONTENT ); // show in the container as well
147 bool ScDocShell::IsOle() const
149 return (GetCreateMode() == SfxObjectCreateMode::EMBEDDED
);
152 void ScDocShell::UpdateOle(const ScViewData
& rViewData
, bool bSnapSize
)
154 // if it isn't Ole at all, one can be spared the calculations
155 // (VisArea will then be reset at the save)
157 if (GetCreateMode() == SfxObjectCreateMode::STANDARD
)
160 tools::Rectangle aOldArea
= SfxObjectShell::GetVisArea();
161 tools::Rectangle aNewArea
= aOldArea
;
163 bool bEmbedded
= m_pDocument
->IsEmbedded();
165 aNewArea
= m_pDocument
->GetEmbeddedRect();
168 SCTAB nTab
= rViewData
.GetTabNo();
169 if ( nTab
!= m_pDocument
->GetVisibleTab() )
170 m_pDocument
->SetVisibleTab( nTab
);
172 bool bNegativePage
= m_pDocument
->IsNegativePage( nTab
);
173 SCCOL nX
= rViewData
.GetPosX(SC_SPLIT_LEFT
);
174 if ( nX
!= m_pDocument
->GetPosLeft() )
175 m_pDocument
->SetPosLeft( nX
);
176 SCROW nY
= rViewData
.GetPosY(SC_SPLIT_BOTTOM
);
177 if ( nY
!= m_pDocument
->GetPosTop() )
178 m_pDocument
->SetPosTop( nY
);
179 tools::Rectangle aMMRect
= m_pDocument
->GetMMRect( nX
,nY
, nX
,nY
, nTab
);
181 lcl_SetTopRight( aNewArea
, aMMRect
.TopRight() );
183 aNewArea
.SetPos( aMMRect
.TopLeft() );
185 SnapVisArea(aNewArea
); // uses the new VisibleTab
188 if (aNewArea
!= aOldArea
)
189 SetVisAreaOrSize( aNewArea
); // the start must also be adjusted here
192 // Style stuff for Organizer, etc.
194 SfxStyleSheetBasePool
* ScDocShell::GetStyleSheetPool()
196 return static_cast<SfxStyleSheetBasePool
*>(m_pDocument
->GetStyleSheetPool());
199 // After loading styles from another document (LoadStyles, Insert), the SetItems
200 // (ATTR_PAGE_HEADERSET, ATTR_PAGE_FOOTERSET) must be converted to the correct pool
201 // before the source pool is deleted.
203 static void lcl_AdjustPool( SfxStyleSheetBasePool
* pStylePool
)
205 SfxStyleSheetBase
*pStyle
= pStylePool
->First(SfxStyleFamily::Page
);
208 SfxItemSet
& rStyleSet
= pStyle
->GetItemSet();
210 if (const SvxSetItem
* pItem
= rStyleSet
.GetItemIfSet(ATTR_PAGE_HEADERSET
,false))
212 const SfxItemSet
& rSrcSet
= pItem
->GetItemSet();
213 SfxItemSet
aDestSet(*rStyleSet
.GetPool(),rSrcSet
.GetRanges());
214 aDestSet
.Put(rSrcSet
);
215 rStyleSet
.Put(SvxSetItem(ATTR_PAGE_HEADERSET
, std::move(aDestSet
)));
217 if (const SvxSetItem
* pItem
= rStyleSet
.GetItemIfSet(ATTR_PAGE_FOOTERSET
,false))
219 const SfxItemSet
& rSrcSet
= pItem
->GetItemSet();
220 SfxItemSet
aDestSet(*rStyleSet
.GetPool(),rSrcSet
.GetRanges());
221 aDestSet
.Put(rSrcSet
);
222 rStyleSet
.Put(SvxSetItem(ATTR_PAGE_FOOTERSET
, std::move(aDestSet
)));
225 pStyle
= pStylePool
->Next();
229 void ScDocShell::LoadStyles( SfxObjectShell
&rSource
)
231 m_pDocument
->getCellAttributeHelper().AllStylesToNames();
233 SfxObjectShell::LoadStyles(rSource
);
234 lcl_AdjustPool( GetStyleSheetPool() ); // adjust SetItems
236 m_pDocument
->getCellAttributeHelper().UpdateAllStyleSheets(*m_pDocument
);
238 UpdateAllRowHeights();
242 PostPaint( 0,0,0, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),MAXTAB
, PaintPartFlags::Grid
| PaintPartFlags::Left
);
245 void ScDocShell::LoadStylesArgs( ScDocShell
& rSource
, bool bReplace
, bool bCellStyles
, bool bPageStyles
)
247 // similar to LoadStyles, but with selectable behavior for XStyleLoader::loadStylesFromURL call
249 if ( !bCellStyles
&& !bPageStyles
) // nothing to do
252 ScStyleSheetPool
* pSourcePool
= rSource
.GetDocument().GetStyleSheetPool();
253 ScStyleSheetPool
* pDestPool
= m_pDocument
->GetStyleSheetPool();
255 SfxStyleFamily eFamily
= bCellStyles
?
256 ( bPageStyles
? SfxStyleFamily::All
: SfxStyleFamily::Para
) :
257 SfxStyleFamily::Page
;
258 SfxStyleSheetIterator
aIter( pSourcePool
, eFamily
);
259 sal_uInt16 nSourceCount
= aIter
.Count();
260 if ( nSourceCount
== 0 )
261 return; // no source styles
263 std::unique_ptr
<ScStylePair
[]> pStyles(new ScStylePair
[ nSourceCount
]);
264 sal_uInt16 nFound
= 0;
266 // first create all new styles
268 SfxStyleSheetBase
* pSourceStyle
= aIter
.First();
271 OUString aName
= pSourceStyle
->GetName();
272 SfxStyleSheetBase
* pDestStyle
= pDestPool
->Find( pSourceStyle
->GetName(), pSourceStyle
->GetFamily() );
275 // touch existing styles only if replace flag is set
278 pStyles
[nFound
].pSource
= pSourceStyle
;
279 pStyles
[nFound
].pDest
= pDestStyle
;
285 pStyles
[nFound
].pSource
= pSourceStyle
;
286 pStyles
[nFound
].pDest
= &pDestPool
->Make( aName
, pSourceStyle
->GetFamily(), pSourceStyle
->GetMask() );
290 pSourceStyle
= aIter
.Next();
293 // then copy contents (after inserting all styles, for parent etc.)
295 for ( sal_uInt16 i
= 0; i
< nFound
; ++i
)
297 pStyles
[i
].pDest
->GetItemSet().PutExtended(
298 pStyles
[i
].pSource
->GetItemSet(), SfxItemState::INVALID
, SfxItemState::DEFAULT
);
299 if(pStyles
[i
].pSource
->HasParentSupport())
300 pStyles
[i
].pDest
->SetParent(pStyles
[i
].pSource
->GetParent());
301 // follow is never used
304 lcl_AdjustPool( GetStyleSheetPool() ); // adjust SetItems
305 UpdateAllRowHeights();
306 PostPaint( 0,0,0, m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),MAXTAB
, PaintPartFlags::Grid
| PaintPartFlags::Left
); // Paint
309 void ScDocShell::ReconnectDdeLink(SfxObjectShell
& rServer
)
311 ::sfx2::LinkManager
* pLinkManager
= m_pDocument
->GetLinkManager();
315 pLinkManager
->ReconnectDdeLink(rServer
);
318 void ScDocShell::UpdateLinks()
320 typedef std::unordered_set
<OUString
> StrSetType
;
322 sfx2::LinkManager
* pLinkManager
= m_pDocument
->GetLinkManager();
325 // out with the no longer used links
327 size_t nCount
= pLinkManager
->GetLinks().size();
328 for (size_t k
=nCount
; k
>0; )
331 ::sfx2::SvBaseLink
* pBase
= pLinkManager
->GetLinks()[k
].get();
332 if (ScTableLink
* pTabLink
= dynamic_cast<ScTableLink
*>(pBase
))
334 if (pTabLink
->IsUsed())
335 aNames
.insert(pTabLink
->GetFileName());
336 else // no longer used -> delete
338 pTabLink
->SetAddUndo(true);
339 pLinkManager
->Remove(k
);
346 SCTAB nTabCount
= m_pDocument
->GetTableCount();
347 for (SCTAB i
= 0; i
< nTabCount
; ++i
)
349 if (!m_pDocument
->IsLinked(i
))
352 OUString aDocName
= m_pDocument
->GetLinkDoc(i
);
353 OUString aFltName
= m_pDocument
->GetLinkFlt(i
);
354 OUString aOptions
= m_pDocument
->GetLinkOpt(i
);
355 sal_Int32 nRefresh
= m_pDocument
->GetLinkRefreshDelay(i
);
357 for (SCTAB j
= 0; j
< i
&& !bThere
; ++j
) // several times in the document?
359 if (m_pDocument
->IsLinked(j
)
360 && m_pDocument
->GetLinkDoc(j
) == aDocName
361 && m_pDocument
->GetLinkFlt(j
) == aFltName
362 && m_pDocument
->GetLinkOpt(j
) == aOptions
)
363 // Ignore refresh delay in compare, it should be the
364 // same for identical links and we don't want dupes
369 if (!bThere
) // already entered as filter?
371 if (!aNames
.insert(aDocName
).second
)
377 ScTableLink
* pLink
= new ScTableLink( this, aDocName
, aFltName
, aOptions
, nRefresh
);
378 pLink
->SetInCreate(true);
379 pLinkManager
->InsertFileLink(*pLink
, sfx2::SvBaseLinkObjectType::ClientFile
, aDocName
, &aFltName
);
381 pLink
->SetInCreate(false);
386 void ScDocShell::ReloadTabLinks()
388 sfx2::LinkManager
* pLinkManager
= m_pDocument
->GetLinkManager();
391 size_t nCount
= pLinkManager
->GetLinks().size();
392 for (size_t i
=0; i
<nCount
; i
++ )
394 ::sfx2::SvBaseLink
* pBase
= pLinkManager
->GetLinks()[i
].get();
395 if (ScTableLink
* pTabLink
= dynamic_cast<ScTableLink
*>(pBase
))
397 // pTabLink->SetAddUndo(sal_False); //! merge Undos
399 // Painting only after Update() makes no sense:
400 // ScTableLink::Refresh() will post a Paint only is bDoPaint is true
401 // pTabLink->SetPaint(false); // Paint only once at the end
403 //pTabLink->SetPaint(true);
404 // pTabLink->SetAddUndo(sal_True);
412 PostPaint( ScRange(0,0,0,m_pDocument
->MaxCol(),m_pDocument
->MaxRow(),MAXTAB
),
413 PaintPartFlags::Grid
| PaintPartFlags::Top
| PaintPartFlags::Left
);
415 SetDocumentModified();
419 void ScDocShell::SetFormulaOptions( const ScFormulaOptions
& rOpt
, bool bForLoading
)
421 m_pDocument
->SetGrammar( rOpt
.GetFormulaSyntax() );
423 // This is nasty because it resets module globals from within a docshell!
424 // For actual damage caused see fdo#82183 where an unconditional
425 // ScGlobal::ResetFunctionList() (without checking GetUseEnglishFuncName())
426 // lead to a crash because the function list was still used by the Formula
427 // Wizard when loading the second document.
428 // Do the stupid stuff only when we're not called while loading a document.
430 /* TODO: bForLoading is a workaround, rather get rid of setting any
431 * globals from per document instances like ScDocShell. */
433 /* XXX this is utter crap, we rely on the options being set here at least
434 * once, for the very first document, empty or loaded. */
435 static bool bInitOnce
= true;
437 if (!bForLoading
|| bInitOnce
)
439 bool bForceInit
= bInitOnce
;
441 if (bForceInit
|| rOpt
.GetUseEnglishFuncName() != ScModule::get()->GetFormulaOptions().GetUseEnglishFuncName())
443 // This needs to be called first since it may re-initialize the entire
445 if (rOpt
.GetUseEnglishFuncName())
447 // switch native symbols to English.
449 ScCompiler
aComp( *m_pDocument
, aAddress
);
450 ScCompiler::OpCodeMapPtr xMap
= aComp
.GetOpCodeMap(css::sheet::FormulaLanguage::ENGLISH
);
451 ScCompiler::SetNativeSymbols(xMap
);
454 // re-initialize native symbols with localized function names.
455 ScCompiler::ResetNativeSymbols();
457 // Force re-population of function names for the function wizard, function tip etc.
458 ScGlobal::ResetFunctionList();
461 // Update the separators.
462 ScCompiler::UpdateSeparatorsNative(
463 rOpt
.GetFormulaSepArg(), rOpt
.GetFormulaSepArrayCol(), rOpt
.GetFormulaSepArrayRow());
465 // Global interpreter settings.
466 ScInterpreter::SetGlobalConfig(rOpt
.GetCalcConfig());
469 // Per document interpreter settings.
470 m_pDocument
->SetCalcConfig( rOpt
.GetCalcConfig() );
473 void ScDocShell::CheckConfigOptions()
475 if (IsConfigOptionsChecked())
476 // no need to check repeatedly.
479 OUString aDecSep
= ScGlobal::getLocaleData().getNumDecimalSep();
480 OUString aDecSepAlt
= ScGlobal::getLocaleData().getNumDecimalSepAlt();
482 ScModule
* pScMod
= ScModule::get();
483 const ScFormulaOptions
& rOpt
=pScMod
->GetFormulaOptions();
484 const OUString
& aSepArg
= rOpt
.GetFormulaSepArg();
485 const OUString
& aSepArrRow
= rOpt
.GetFormulaSepArrayRow();
486 const OUString
& aSepArrCol
= rOpt
.GetFormulaSepArrayCol();
488 if (aDecSep
== aSepArg
|| aDecSep
== aSepArrRow
|| aDecSep
== aSepArrCol
||
489 aDecSepAlt
== aSepArg
|| aDecSepAlt
== aSepArrRow
|| aDecSepAlt
== aSepArrCol
)
491 // One of arg separators conflicts with the current decimal
492 // separator. Reset them to default.
493 ScFormulaOptions aNew
= rOpt
;
494 aNew
.ResetFormulaSeparators();
495 SetFormulaOptions(aNew
);
496 pScMod
->SetFormulaOptions(aNew
);
498 // Launch a nice warning dialog to let the users know of this change.
499 ScTabViewShell
* pViewShell
= comphelper::LibreOfficeKit::isActive() ? nullptr : GetBestViewShell();
502 std::shared_ptr
<weld::MessageDialog
> xInfoBox(Application::CreateMessageDialog(pViewShell
->GetFrameWeld(),
503 VclMessageType::Info
, VclButtonsType::Ok
,
504 ScResId(STR_OPTIONS_WARN_SEPARATORS
), pViewShell
));
505 xInfoBox
->runAsync(xInfoBox
, [] (int) {});
508 // For now, this is the only option setting that could launch info
509 // dialog. But in the future we may want to implement a nicer
510 // dialog to display a list of warnings in case we have several
511 // pieces of information to display.
514 SetConfigOptionsChecked(true);
517 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */