fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / docshell / arealink.cxx
blobb4c33ef08be6db02fee8fbadf593e3a6ec44aaa5
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <comphelper/string.hxx>
21 #include <sfx2/app.hxx>
22 #include <sfx2/docfile.hxx>
23 #include <sfx2/fcontnr.hxx>
24 #include <sfx2/linkmgr.hxx>
25 #include <svl/stritem.hxx>
26 #include <vcl/msgbox.hxx>
28 #include "arealink.hxx"
30 #include "tablink.hxx"
31 #include "document.hxx"
32 #include "docsh.hxx"
33 #include "rangenam.hxx"
34 #include "dbdata.hxx"
35 #include "undoblk.hxx"
36 #include "globstr.hrc"
37 #include "markdata.hxx"
38 #include "hints.hxx"
39 #include "filter.hxx"
41 #include "attrib.hxx"
42 #include "patattr.hxx"
43 #include "docpool.hxx"
45 #include "sc.hrc"
46 #include "scabstdlg.hxx"
47 #include "clipparam.hxx"
49 struct AreaLink_Impl
51 ScDocShell* m_pDocSh;
52 AbstractScLinkedAreaDlg* m_pDialog;
54 AreaLink_Impl() : m_pDocSh( NULL ), m_pDialog( NULL ) {}
57 TYPEINIT1(ScAreaLink,::sfx2::SvBaseLink);
59 ScAreaLink::ScAreaLink( SfxObjectShell* pShell, const OUString& rFile,
60 const OUString& rFilter, const OUString& rOpt,
61 const OUString& rArea, const ScRange& rDest,
62 sal_uLong nRefresh ) :
63 ::sfx2::SvBaseLink(SfxLinkUpdateMode::ONCALL,SotClipboardFormatId::SIMPLE_FILE),
64 ScRefreshTimer ( nRefresh ),
65 pImpl ( new AreaLink_Impl() ),
66 aFileName (rFile),
67 aFilterName (rFilter),
68 aOptions (rOpt),
69 aSourceArea (rArea),
70 aDestArea (rDest),
71 bAddUndo (true),
72 bInCreate (false),
73 bDoInsert (true)
75 OSL_ENSURE(pShell->ISA(ScDocShell), "ScAreaLink mit falscher ObjectShell");
76 pImpl->m_pDocSh = static_cast< ScDocShell* >( pShell );
77 SetRefreshHandler( LINK( this, ScAreaLink, RefreshHdl ) );
78 SetRefreshControl( &pImpl->m_pDocSh->GetDocument().GetRefreshTimerControlAddress() );
81 ScAreaLink::~ScAreaLink()
83 StopRefreshTimer();
84 delete pImpl;
87 void ScAreaLink::Edit(vcl::Window* pParent, const Link<>& /* rEndEditHdl */ )
89 // use own dialog instead of SvBaseLink::Edit...
90 // DefModalDialogParent setzen, weil evtl. aus der DocShell beim ConvertFrom
91 // ein Optionen-Dialog kommt...
93 ScAbstractDialogFactory* pFact = ScAbstractDialogFactory::Create();
94 OSL_ENSURE(pFact, "ScAbstractFactory create fail!");
96 AbstractScLinkedAreaDlg* pDlg = pFact->CreateScLinkedAreaDlg(pParent);
97 OSL_ENSURE(pDlg, "Dialog create fail!");
98 pDlg->InitFromOldLink( aFileName, aFilterName, aOptions, aSourceArea, GetRefreshDelay() );
99 pImpl->m_pDialog = pDlg;
100 pDlg->StartExecuteModal( LINK( this, ScAreaLink, AreaEndEditHdl ) );
103 ::sfx2::SvBaseLink::UpdateResult ScAreaLink::DataChanged(
104 const OUString&, const ::com::sun::star::uno::Any& )
106 // bei bInCreate nichts tun, damit Update gerufen werden kann, um den Status im
107 // LinkManager zu setzen, ohne die Daten im Dokument zu aendern
109 if (bInCreate)
110 return SUCCESS;
112 sfx2::LinkManager* pLinkManager=pImpl->m_pDocSh->GetDocument().GetLinkManager();
113 if (pLinkManager!=NULL)
115 OUString aFile, aArea, aFilter;
116 sfx2::LinkManager::GetDisplayNames(this, NULL, &aFile, &aArea, &aFilter);
118 // the file dialog returns the filter name with the application prefix
119 // -> remove prefix
120 ScDocumentLoader::RemoveAppPrefix( aFilter );
122 // dialog doesn't set area, so keep old one
123 if (aArea.isEmpty())
125 aArea = aSourceArea;
127 // adjust in dialog:
128 OUString aNewLinkName;
129 OUString aTmp = aFilter;
130 sfx2::MakeLnkName(aNewLinkName, NULL, aFile, aArea, &aTmp);
131 aFilter = aTmp;
132 SetName( aNewLinkName );
135 sfx2::SvBaseLinkRef const xThis(this); // keep yourself alive
136 Refresh( aFile, aFilter, aArea, GetRefreshDelay() );
139 return SUCCESS;
142 void ScAreaLink::Closed()
144 // Verknuepfung loeschen: Undo
146 ScDocument& rDoc = pImpl->m_pDocSh->GetDocument();
147 bool bUndo (rDoc.IsUndoEnabled());
148 if (bAddUndo && bUndo)
150 pImpl->m_pDocSh->GetUndoManager()->AddUndoAction( new ScUndoRemoveAreaLink( pImpl->m_pDocSh,
151 aFileName, aFilterName, aOptions,
152 aSourceArea, aDestArea, GetRefreshDelay() ) );
154 bAddUndo = false; // nur einmal
157 SCTAB nDestTab = aDestArea.aStart.Tab();
158 if (rDoc.IsStreamValid(nDestTab))
159 rDoc.SetStreamValid(nDestTab, false);
161 SvBaseLink::Closed();
164 void ScAreaLink::SetDestArea(const ScRange& rNew)
166 aDestArea = rNew; // fuer Undo
169 void ScAreaLink::SetSource(const OUString& rDoc, const OUString& rFlt, const OUString& rOpt,
170 const OUString& rArea)
172 aFileName = rDoc;
173 aFilterName = rFlt;
174 aOptions = rOpt;
175 aSourceArea = rArea;
177 // also update link name for dialog
178 OUString aNewLinkName;
179 sfx2::MakeLnkName( aNewLinkName, NULL, aFileName, aSourceArea, &aFilterName );
180 SetName( aNewLinkName );
183 bool ScAreaLink::IsEqual( const OUString& rFile, const OUString& rFilter, const OUString& rOpt,
184 const OUString& rSource, const ScRange& rDest ) const
186 return aFileName == rFile && aFilterName == rFilter && aOptions == rOpt &&
187 aSourceArea == rSource && aDestArea.aStart == rDest.aStart;
190 // find a range with name >rAreaName< in >pSrcDoc<, return it in >rRange<
191 bool ScAreaLink::FindExtRange( ScRange& rRange, ScDocument* pSrcDoc, const OUString& rAreaName )
193 bool bFound = false;
194 OUString aUpperName = ScGlobal::pCharClass->uppercase(rAreaName);
195 ScRangeName* pNames = pSrcDoc->GetRangeName();
196 if (pNames) // benannte Bereiche
198 const ScRangeData* p = pNames->findByUpperName(aUpperName);
199 if (p && p->IsValidReference(rRange))
200 bFound = true;
202 if (!bFound) // Datenbankbereiche
204 ScDBCollection* pDBColl = pSrcDoc->GetDBCollection();
205 if (pDBColl)
207 const ScDBData* pDB = pDBColl->getNamedDBs().findByUpperName(aUpperName);
208 if (pDB)
210 SCTAB nTab;
211 SCCOL nCol1, nCol2;
212 SCROW nRow1, nRow2;
213 pDB->GetArea(nTab,nCol1,nRow1,nCol2,nRow2);
214 rRange = ScRange( nCol1,nRow1,nTab, nCol2,nRow2,nTab );
215 bFound = true;
219 if (!bFound) // direct reference (range or cell)
221 ScAddress::Details aDetails(pSrcDoc->GetAddressConvention(), 0, 0);
222 if ( rRange.ParseAny( rAreaName, pSrcDoc, aDetails ) & SCA_VALID )
223 bFound = true;
225 return bFound;
228 // ausfuehren:
230 bool ScAreaLink::Refresh( const OUString& rNewFile, const OUString& rNewFilter,
231 const OUString& rNewArea, sal_uLong nNewRefresh )
233 // Dokument laden - wie TabLink
235 if (rNewFile.isEmpty() || rNewFilter.isEmpty())
236 return false;
238 OUString aNewUrl( ScGlobal::GetAbsDocName( rNewFile, pImpl->m_pDocSh ) );
239 bool bNewUrlName = (aNewUrl != aFileName);
241 const SfxFilter* pFilter = pImpl->m_pDocSh->GetFactory().GetFilterContainer()->GetFilter4FilterName(rNewFilter);
242 if (!pFilter)
243 return false;
245 ScDocument& rDoc = pImpl->m_pDocSh->GetDocument();
247 bool bUndo (rDoc.IsUndoEnabled());
248 rDoc.SetInLinkUpdate( true );
250 // wenn neuer Filter ausgewaehlt wurde, Optionen vergessen
251 if ( rNewFilter != aFilterName )
252 aOptions.clear();
254 SfxMedium* pMed = ScDocumentLoader::CreateMedium( aNewUrl, pFilter, aOptions);
256 // aRef->DoClose() will be closed explicitly, but it is still more safe to use SfxObjectShellLock here
257 ScDocShell* pSrcShell = new ScDocShell(SfxModelFlags::EMBEDDED_OBJECT | SfxModelFlags::DISABLE_EMBEDDED_SCRIPTS);
258 SfxObjectShellLock aRef = pSrcShell;
259 pSrcShell->DoLoad(pMed);
261 ScDocument& rSrcDoc = pSrcShell->GetDocument();
263 // Optionen koennten gesetzt worden sein
264 OUString aNewOpt = ScDocumentLoader::GetOptions(*pMed);
265 if (aNewOpt.isEmpty())
266 aNewOpt = aOptions;
268 // correct source range name list for web query import
269 OUString aTempArea;
271 if( rNewFilter == ScDocShell::GetWebQueryFilterName() )
272 aTempArea = ScFormatFilter::Get().GetHTMLRangeNameList( &rSrcDoc, rNewArea );
273 else
274 aTempArea = rNewArea;
276 // find total size of source area
277 SCCOL nWidth = 0;
278 SCROW nHeight = 0;
279 sal_Int32 nTokenCnt = comphelper::string::getTokenCount(aTempArea, ';');
280 sal_Int32 nStringIx = 0;
281 sal_Int32 nToken;
283 for( nToken = 0; nToken < nTokenCnt; nToken++ )
285 OUString aToken( aTempArea.getToken( 0, ';', nStringIx ) );
286 ScRange aTokenRange;
287 if( FindExtRange( aTokenRange, &rSrcDoc, aToken ) )
289 // columns: find maximum
290 nWidth = std::max( nWidth, (SCCOL)(aTokenRange.aEnd.Col() - aTokenRange.aStart.Col() + 1) );
291 // rows: add row range + 1 empty row
292 nHeight += aTokenRange.aEnd.Row() - aTokenRange.aStart.Row() + 2;
295 // remove the last empty row
296 if( nHeight > 0 )
297 nHeight--;
299 // alte Daten loeschen / neue kopieren
301 ScAddress aDestPos = aDestArea.aStart;
302 SCTAB nDestTab = aDestPos.Tab();
303 ScRange aOldRange = aDestArea;
304 ScRange aNewRange = aDestArea; // alter Bereich, wenn Datei nicht gefunden o.ae.
305 if (nWidth > 0 && nHeight > 0)
307 aNewRange.aEnd.SetCol( aNewRange.aStart.Col() + nWidth - 1 );
308 aNewRange.aEnd.SetRow( aNewRange.aStart.Row() + nHeight - 1 );
311 //! check CanFitBlock only if bDoInsert is set?
312 bool bCanDo = ValidColRow( aNewRange.aEnd.Col(), aNewRange.aEnd.Row() ) &&
313 rDoc.CanFitBlock( aOldRange, aNewRange );
314 if (bCanDo)
316 ScDocShellModificator aModificator( *pImpl->m_pDocSh );
318 SCCOL nOldEndX = aOldRange.aEnd.Col();
319 SCROW nOldEndY = aOldRange.aEnd.Row();
320 SCCOL nNewEndX = aNewRange.aEnd.Col();
321 SCROW nNewEndY = aNewRange.aEnd.Row();
322 ScRange aMaxRange( aDestPos,
323 ScAddress(std::max(nOldEndX,nNewEndX), std::max(nOldEndY,nNewEndY), nDestTab) );
325 // Undo initialisieren
327 ScDocument* pUndoDoc = NULL;
328 if ( bAddUndo && bUndo )
330 pUndoDoc = new ScDocument( SCDOCMODE_UNDO );
331 if ( bDoInsert )
333 if ( nNewEndX != nOldEndX || nNewEndY != nOldEndY ) // Bereich veraendert?
335 pUndoDoc->InitUndo( &rDoc, 0, rDoc.GetTableCount()-1 );
336 rDoc.CopyToDocument( 0,0,0,MAXCOL,MAXROW,MAXTAB,
337 IDF_FORMULA, false, pUndoDoc ); // alle Formeln
339 else
340 pUndoDoc->InitUndo( &rDoc, nDestTab, nDestTab ); // nur Zieltabelle
341 rDoc.CopyToDocument( aOldRange, IDF_ALL & ~IDF_NOTE, false, pUndoDoc );
343 else // ohne Einfuegen
345 pUndoDoc->InitUndo( &rDoc, nDestTab, nDestTab ); // nur Zieltabelle
346 rDoc.CopyToDocument( aMaxRange, IDF_ALL & ~IDF_NOTE, false, pUndoDoc );
350 // Zellen einfuegen / loeschen
351 // DeleteAreaTab loescht auch MERGE_FLAG Attribute
353 if (bDoInsert)
354 rDoc.FitBlock( aOldRange, aNewRange ); // incl. loeschen
355 else
356 rDoc.DeleteAreaTab( aMaxRange, IDF_ALL & ~IDF_NOTE );
358 // Daten kopieren
360 if (nWidth > 0 && nHeight > 0)
362 ScDocument aClipDoc( SCDOCMODE_CLIP );
363 ScRange aNewTokenRange( aNewRange.aStart );
364 nStringIx = 0;
365 for( nToken = 0; nToken < nTokenCnt; nToken++ )
367 OUString aToken( aTempArea.getToken( 0, ';', nStringIx ) );
368 ScRange aTokenRange;
369 if( FindExtRange( aTokenRange, &rSrcDoc, aToken ) )
371 SCTAB nSrcTab = aTokenRange.aStart.Tab();
372 ScMarkData aSourceMark;
373 aSourceMark.SelectOneTable( nSrcTab ); // selektieren fuer CopyToClip
374 aSourceMark.SetMarkArea( aTokenRange );
376 ScClipParam aClipParam(aTokenRange, false);
377 rSrcDoc.CopyToClip(aClipParam, &aClipDoc, &aSourceMark);
379 if ( aClipDoc.HasAttrib( 0,0,nSrcTab, MAXCOL,MAXROW,nSrcTab,
380 HASATTR_MERGED | HASATTR_OVERLAPPED ) )
382 //! ResetAttrib am Dokument !!!
384 ScPatternAttr aPattern( rSrcDoc.GetPool() );
385 aPattern.GetItemSet().Put( ScMergeAttr() ); // Defaults
386 aPattern.GetItemSet().Put( ScMergeFlagAttr() );
387 aClipDoc.ApplyPatternAreaTab( 0,0, MAXCOL,MAXROW, nSrcTab, aPattern );
390 aNewTokenRange.aEnd.SetCol( aNewTokenRange.aStart.Col() + (aTokenRange.aEnd.Col() - aTokenRange.aStart.Col()) );
391 aNewTokenRange.aEnd.SetRow( aNewTokenRange.aStart.Row() + (aTokenRange.aEnd.Row() - aTokenRange.aStart.Row()) );
392 ScMarkData aDestMark;
393 aDestMark.SelectOneTable( nDestTab );
394 aDestMark.SetMarkArea( aNewTokenRange );
395 rDoc.CopyFromClip( aNewTokenRange, aDestMark, IDF_ALL, NULL, &aClipDoc, false );
396 aNewTokenRange.aStart.SetRow( aNewTokenRange.aEnd.Row() + 2 );
400 else
402 OUString aErr = ScGlobal::GetRscString(STR_LINKERROR);
403 rDoc.SetString( aDestPos.Col(), aDestPos.Row(), aDestPos.Tab(), aErr );
406 // Undo eintragen
408 if ( bAddUndo && bUndo)
410 ScDocument* pRedoDoc = new ScDocument( SCDOCMODE_UNDO );
411 pRedoDoc->InitUndo( &rDoc, nDestTab, nDestTab );
412 rDoc.CopyToDocument( aNewRange, IDF_ALL & ~IDF_NOTE, false, pRedoDoc );
414 pImpl->m_pDocSh->GetUndoManager()->AddUndoAction(
415 new ScUndoUpdateAreaLink( pImpl->m_pDocSh,
416 aFileName, aFilterName, aOptions,
417 aSourceArea, aOldRange, GetRefreshDelay(),
418 aNewUrl, rNewFilter, aNewOpt,
419 rNewArea, aNewRange, nNewRefresh,
420 pUndoDoc, pRedoDoc, bDoInsert ) );
423 // neue Einstellungen merken
425 if ( bNewUrlName )
426 aFileName = aNewUrl;
427 if ( rNewFilter != aFilterName )
428 aFilterName = rNewFilter;
429 if ( rNewArea != aSourceArea )
430 aSourceArea = rNewArea;
431 if ( aNewOpt != aOptions )
432 aOptions = aNewOpt;
434 if ( aNewRange != aDestArea )
435 aDestArea = aNewRange;
437 if ( nNewRefresh != GetRefreshDelay() )
438 SetRefreshDelay( nNewRefresh );
440 SCCOL nPaintEndX = std::max( aOldRange.aEnd.Col(), aNewRange.aEnd.Col() );
441 SCROW nPaintEndY = std::max( aOldRange.aEnd.Row(), aNewRange.aEnd.Row() );
443 if ( aOldRange.aEnd.Col() != aNewRange.aEnd.Col() )
444 nPaintEndX = MAXCOL;
445 if ( aOldRange.aEnd.Row() != aNewRange.aEnd.Row() )
446 nPaintEndY = MAXROW;
448 if ( !pImpl->m_pDocSh->AdjustRowHeight( aDestPos.Row(), nPaintEndY, nDestTab ) )
449 pImpl->m_pDocSh->PostPaint(
450 ScRange(aDestPos.Col(), aDestPos.Row(), nDestTab, nPaintEndX, nPaintEndY, nDestTab),
451 PAINT_GRID);
452 aModificator.SetDocumentModified();
454 else
456 // CanFitBlock sal_False -> Probleme mit zusammengefassten Zellen
457 // oder Tabellengrenze erreicht!
458 //! Zellschutz ???
460 //! Link-Dialog muss Default-Parent setzen
461 // "kann keine Zeilen einfuegen"
462 ScopedVclPtrInstance<InfoBox> aBox( Application::GetDefDialogParent(),
463 ScGlobal::GetRscString( STR_MSSG_DOSUBTOTALS_2 ) );
464 aBox->Execute();
467 // aufraeumen
469 aRef->DoClose();
471 rDoc.SetInLinkUpdate( false );
473 if (bCanDo)
475 // notify Uno objects (for XRefreshListener)
476 //! also notify Uno objects if file name was changed!
477 ScLinkRefreshedHint aHint;
478 aHint.SetAreaLink( aDestPos );
479 rDoc.BroadcastUno( aHint );
482 return bCanDo;
485 IMPL_LINK_NOARG_TYPED(ScAreaLink, RefreshHdl, Timer *, void)
487 Refresh( aFileName, aFilterName, aSourceArea, GetRefreshDelay() );
490 IMPL_LINK_NOARG(ScAreaLink, AreaEndEditHdl)
492 // #i76514# can't use link argument to access the dialog,
493 // because it's the ScLinkedAreaDlg, not AbstractScLinkedAreaDlg
495 if ( pImpl->m_pDialog && pImpl->m_pDialog->GetResult() == RET_OK )
497 aOptions = pImpl->m_pDialog->GetOptions();
498 Refresh( pImpl->m_pDialog->GetURL(), pImpl->m_pDialog->GetFilter(),
499 pImpl->m_pDialog->GetSource(), pImpl->m_pDialog->GetRefresh() );
501 // copy source data from members (set in Refresh) into link name for dialog
502 OUString aNewLinkName;
503 sfx2::MakeLnkName( aNewLinkName, NULL, aFileName, aSourceArea, &aFilterName );
504 SetName( aNewLinkName );
506 pImpl->m_pDialog = NULL; // dialog is deleted with parent
508 return 0;
511 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */