/src/libreoffice/sfx2/source/doc/objcont.cxx
Line | Count | Source |
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 | | |
21 | | #include <com/sun/star/uno/Reference.hxx> |
22 | | |
23 | | #include <com/sun/star/document/DocumentProperties.hpp> |
24 | | #include <com/sun/star/document/XDocumentProperties.hpp> |
25 | | #include <com/sun/star/document/UpdateDocMode.hpp> |
26 | | #include <comphelper/fileurl.hxx> |
27 | | #include <vcl/svapp.hxx> |
28 | | #include <vcl/weld.hxx> |
29 | | #include <svl/style.hxx> |
30 | | |
31 | | #include <svl/intitem.hxx> |
32 | | #include <svl/itemset.hxx> |
33 | | #include <svl/eitem.hxx> |
34 | | #include <svl/ctloptions.hxx> |
35 | | #include <comphelper/processfactory.hxx> |
36 | | #include <unotools/securityoptions.hxx> |
37 | | #include <tools/datetime.hxx> |
38 | | #include <tools/debug.hxx> |
39 | | #include <comphelper/diagnose_ex.hxx> |
40 | | #include <tools/helpers.hxx> |
41 | | #include <rtl/uri.hxx> |
42 | | |
43 | | #include <unotools/useroptions.hxx> |
44 | | #include <vcl/virdev.hxx> |
45 | | #include <vcl/settings.hxx> |
46 | | #include <vcl/gdimtf.hxx> |
47 | | |
48 | | #include <sfx2/app.hxx> |
49 | | #include <sfx2/dinfdlg.hxx> |
50 | | #include <sfx2/sfxresid.hxx> |
51 | | #include <appdata.hxx> |
52 | | #include <sfx2/docfac.hxx> |
53 | | #include <sfx2/viewsh.hxx> |
54 | | #include <sfx2/objsh.hxx> |
55 | | #include <objshimp.hxx> |
56 | | #include <sfx2/printer.hxx> |
57 | | #include <sfx2/viewfrm.hxx> |
58 | | #include <sfx2/doctempl.hxx> |
59 | | #include <sfx2/sfxsids.hrc> |
60 | | #include <sfx2/strings.hrc> |
61 | | #include <sfx2/docfile.hxx> |
62 | | #include <sfx2/docfilt.hxx> |
63 | | #include <sfx2/IDocumentModelAccessor.hxx> |
64 | | #include <memory> |
65 | | #include <helpids.h> |
66 | | |
67 | | using namespace ::com::sun::star; |
68 | | using namespace ::com::sun::star::uno; |
69 | | |
70 | | |
71 | | static |
72 | | bool operator> (const util::DateTime& i_rLeft, const util::DateTime& i_rRight) |
73 | 0 | { |
74 | 0 | if ( i_rLeft.Year != i_rRight.Year ) |
75 | 0 | return i_rLeft.Year > i_rRight.Year; |
76 | | |
77 | 0 | if ( i_rLeft.Month != i_rRight.Month ) |
78 | 0 | return i_rLeft.Month > i_rRight.Month; |
79 | | |
80 | 0 | if ( i_rLeft.Day != i_rRight.Day ) |
81 | 0 | return i_rLeft.Day > i_rRight.Day; |
82 | | |
83 | 0 | if ( i_rLeft.Hours != i_rRight.Hours ) |
84 | 0 | return i_rLeft.Hours > i_rRight.Hours; |
85 | | |
86 | 0 | if ( i_rLeft.Minutes != i_rRight.Minutes ) |
87 | 0 | return i_rLeft.Minutes > i_rRight.Minutes; |
88 | | |
89 | 0 | if ( i_rLeft.Seconds != i_rRight.Seconds ) |
90 | 0 | return i_rLeft.Seconds > i_rRight.Seconds; |
91 | | |
92 | 0 | if ( i_rLeft.NanoSeconds != i_rRight.NanoSeconds ) |
93 | 0 | return i_rLeft.NanoSeconds > i_rRight.NanoSeconds; |
94 | | |
95 | 0 | return false; |
96 | 0 | } |
97 | | |
98 | | std::shared_ptr<GDIMetaFile> |
99 | | SfxObjectShell::GetPreviewMetaFile( bool bFullContent, bool bOutputForScreen ) const |
100 | 0 | { |
101 | 0 | auto xFile = std::make_shared<GDIMetaFile>(); |
102 | 0 | ScopedVclPtrInstance< VirtualDevice > pDevice; |
103 | 0 | pDevice->EnableOutput( false ); |
104 | 0 | if(!CreatePreview_Impl(bFullContent, bOutputForScreen, pDevice, xFile.get())) |
105 | 0 | return std::shared_ptr<GDIMetaFile>(); |
106 | 0 | return xFile; |
107 | 0 | } |
108 | | |
109 | | Bitmap SfxObjectShell::GetPreviewBitmap() const |
110 | 0 | { |
111 | 0 | SfxCloseVetoLock lock(this); |
112 | 0 | ScopedVclPtrInstance< VirtualDevice > pDevice(DeviceFormat::WITH_ALPHA); |
113 | 0 | pDevice->SetAntialiasing(AntialiasingFlags::Enable | pDevice->GetAntialiasing()); |
114 | 0 | if(!CreatePreview_Impl(/*bFullContent*/false, false, pDevice, nullptr)) |
115 | 0 | return Bitmap(); |
116 | 0 | Size size = pDevice->GetOutputSizePixel(); |
117 | 0 | Bitmap aBitmap( pDevice->GetBitmap( Point(), size) ); |
118 | | // Scale down the image to the desired size from the 4*size from CreatePreview_Impl(). |
119 | 0 | size = Size( size.Width() / 4, size.Height() / 4 ); |
120 | 0 | aBitmap.Scale(size, BmpScaleFlag::BestQuality); |
121 | 0 | if (!aBitmap.IsEmpty()) |
122 | 0 | aBitmap.Convert(BmpConversion::N24Bit); |
123 | 0 | return aBitmap; |
124 | 0 | } |
125 | | |
126 | | bool SfxObjectShell::CreatePreview_Impl( bool bFullContent, bool bOutputForScreen, VirtualDevice* pDevice, GDIMetaFile* pFile) const |
127 | 0 | { |
128 | | // DoDraw can only be called when no printing is done, otherwise |
129 | | // the printer may be turned off |
130 | 0 | SfxViewFrame *pFrame = SfxViewFrame::GetFirst( this ); |
131 | 0 | if ( pFrame && pFrame->GetViewShell() && |
132 | 0 | pFrame->GetViewShell()->GetPrinter() && |
133 | 0 | pFrame->GetViewShell()->GetPrinter()->IsPrinting() ) |
134 | 0 | return false; |
135 | | |
136 | 0 | MapMode aMode( GetMapUnit() ); |
137 | 0 | Size aTmpSize; |
138 | 0 | sal_Int8 nAspect; |
139 | 0 | if ( bFullContent ) |
140 | 0 | { |
141 | 0 | nAspect = ASPECT_CONTENT; |
142 | 0 | aTmpSize = GetVisArea( nAspect ).GetSize(); |
143 | 0 | } |
144 | 0 | else |
145 | 0 | { |
146 | 0 | nAspect = ASPECT_THUMBNAIL; |
147 | 0 | aTmpSize = GetFirstPageSize(); |
148 | 0 | } |
149 | |
|
150 | 0 | DBG_ASSERT( !aTmpSize.IsEmpty(), |
151 | 0 | "size of first page is 0, override GetFirstPageSize or set visible-area!" ); |
152 | |
|
153 | 0 | if(pFile) |
154 | 0 | { |
155 | 0 | pDevice->SetMapMode( aMode ); |
156 | 0 | pFile->SetPrefMapMode( aMode ); |
157 | 0 | pFile->SetPrefSize( aTmpSize ); |
158 | 0 | pFile->Record( pDevice ); |
159 | 0 | } |
160 | 0 | else |
161 | 0 | { |
162 | | // Use pixel size, that's also what DoDraw() requires in this case, |
163 | | // despite the metafile case (needlessly?) setting mapmode. |
164 | 0 | Size aSizePix = pDevice->LogicToPixel( aTmpSize, aMode ); |
165 | | // Code based on GDIMetaFile::CreateThumbnail(). |
166 | 0 | sal_uInt32 nMaximumExtent = 512; |
167 | | // determine size that has the same aspect ratio as image size and |
168 | | // fits into the rectangle determined by nMaximumExtent |
169 | 0 | if ( aSizePix.Width() && aSizePix.Height() |
170 | 0 | && ( sal::static_int_cast< tools::ULong >(aSizePix.Width()) > |
171 | 0 | nMaximumExtent || |
172 | 0 | sal::static_int_cast< tools::ULong >(aSizePix.Height()) > |
173 | 0 | nMaximumExtent ) ) |
174 | 0 | { |
175 | 0 | double fWH = static_cast< double >( aSizePix.Width() ) / aSizePix.Height(); |
176 | 0 | if ( fWH <= 1.0 ) |
177 | 0 | { |
178 | 0 | aSizePix.setWidth(basegfx::fround<tools::Long>(nMaximumExtent * fWH)); |
179 | 0 | aSizePix.setHeight( nMaximumExtent ); |
180 | 0 | } |
181 | 0 | else |
182 | 0 | { |
183 | 0 | aSizePix.setWidth( nMaximumExtent ); |
184 | 0 | aSizePix.setHeight(basegfx::fround<tools::Long>(nMaximumExtent / fWH)); |
185 | 0 | } |
186 | 0 | } |
187 | | // do it 4x larger to be able to scale it down & get beautiful antialias |
188 | 0 | aTmpSize = Size( aSizePix.Width() * 4, aSizePix.Height() * 4 ); |
189 | 0 | pDevice->SetOutputSizePixel( aTmpSize ); |
190 | 0 | } |
191 | |
|
192 | 0 | LanguageType eLang; |
193 | 0 | if ( SvtCTLOptions::NUMERALS_HINDI == SvtCTLOptions::GetCTLTextNumerals() ) |
194 | 0 | eLang = LANGUAGE_ARABIC_SAUDI_ARABIA; |
195 | 0 | else if ( SvtCTLOptions::NUMERALS_ARABIC == SvtCTLOptions::GetCTLTextNumerals() ) |
196 | 0 | eLang = LANGUAGE_ENGLISH; |
197 | 0 | else |
198 | 0 | eLang = Application::GetSettings().GetLanguageTag().getLanguageType(); |
199 | |
|
200 | 0 | pDevice->SetDigitLanguage( eLang ); |
201 | |
|
202 | 0 | const_cast<SfxObjectShell*>(this)->DoDraw( pDevice, Point(0,0), aTmpSize, JobSetup(), nAspect, bOutputForScreen ); |
203 | |
|
204 | 0 | if(pFile) |
205 | 0 | pFile->Stop(); |
206 | |
|
207 | 0 | return true; |
208 | 0 | } |
209 | | |
210 | | |
211 | | void SfxObjectShell::UpdateDocInfoForSave() |
212 | 0 | { |
213 | 0 | uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); |
214 | | |
215 | | // clear user data if recommend (see 'Tools - Options - LibreOffice - Security') |
216 | 0 | if ( SvtSecurityOptions::IsOptionSet( |
217 | 0 | SvtSecurityOptions::EOption::DocWarnRemovePersonalInfo ) && !SvtSecurityOptions::IsOptionSet( |
218 | 0 | SvtSecurityOptions::EOption::DocWarnKeepDocUserInfo)) |
219 | 0 | { |
220 | 0 | xDocProps->resetUserData( OUString() ); |
221 | 0 | } |
222 | 0 | else if ( IsModified() ) |
223 | 0 | { |
224 | 0 | const OUString aUserName = SvtUserOptions().GetFullName(); |
225 | 0 | if ( !IsUseUserData() ) |
226 | 0 | { |
227 | | // remove all data pointing to the current user |
228 | 0 | if (xDocProps->getAuthor() == aUserName) { |
229 | 0 | xDocProps->setAuthor( OUString() ); |
230 | 0 | } |
231 | 0 | xDocProps->setModifiedBy( OUString() ); |
232 | 0 | if (xDocProps->getPrintedBy() == aUserName) { |
233 | 0 | xDocProps->setPrintedBy( OUString() ); |
234 | 0 | } |
235 | 0 | } |
236 | 0 | else |
237 | 0 | { |
238 | | // update ModificationAuthor, revision and editing time |
239 | 0 | ::DateTime now( ::DateTime::SYSTEM ); |
240 | 0 | xDocProps->setModificationDate( now.GetUNODateTime() ); |
241 | 0 | xDocProps->setModifiedBy( aUserName ); |
242 | 0 | if (!SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemoveEditingTimeInfo)) |
243 | 0 | UpdateTime_Impl( xDocProps ); |
244 | 0 | } |
245 | | // reset only editing time to zero if RemoveEditingTimeOnSaving is true |
246 | 0 | if (SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemoveEditingTimeInfo)) |
247 | 0 | xDocProps->setEditingDuration(0); |
248 | 0 | } |
249 | 0 | else |
250 | 0 | { |
251 | | // reset only editing time to zero if RemoveEditingTimeOnSaving is true |
252 | 0 | if (SvtSecurityOptions::IsOptionSet(SvtSecurityOptions::EOption::DocWarnRemoveEditingTimeInfo)) |
253 | 0 | xDocProps->setEditingDuration(0); |
254 | 0 | } |
255 | 0 | } |
256 | | |
257 | | |
258 | | static void |
259 | | lcl_add(util::Duration & rDur, tools::Time const& rTime) |
260 | 0 | { |
261 | | // here we don't care about overflow: rDur is converted back to seconds |
262 | | // anyway, and tools::Time cannot store more than ~4000 hours |
263 | 0 | rDur.Hours += rTime.GetHour(); |
264 | 0 | rDur.Minutes += rTime.GetMin(); |
265 | 0 | rDur.Seconds += rTime.GetSec(); |
266 | 0 | } |
267 | | |
268 | | // Update the processing time |
269 | | void SfxObjectShell::UpdateTime_Impl( |
270 | | const uno::Reference<document::XDocumentProperties> & i_xDocProps) |
271 | 0 | { |
272 | | // Get old time from documentinfo |
273 | 0 | const sal_Int32 secs = i_xDocProps->getEditingDuration(); |
274 | 0 | util::Duration editDuration(false, 0, 0, 0, |
275 | 0 | secs/3600, (secs%3600)/60, secs%60, 0); |
276 | | |
277 | | // Initialize some local member! It's necessary for follow operations! |
278 | 0 | DateTime aNow( DateTime::SYSTEM ); // Date and time at current moment |
279 | | |
280 | | // Save impossible cases! |
281 | | // User has changed time to the past between last editing and now... it's not possible!!! |
282 | 0 | DBG_ASSERT( !(aNow.GetDate()<pImpl->nTime.GetDate()), "Timestamp of last change is in the past!?..." ); |
283 | | |
284 | | // Do the follow only, if user has NOT changed time to the past. |
285 | | // Else add a time of 0 to aOldTime... !!! |
286 | 0 | if (aNow.GetDate()>=pImpl->nTime.GetDate()) |
287 | 0 | { |
288 | | // Count of days between now and last editing |
289 | 0 | sal_Int32 nDays = aNow.GetSecFromDateTime(Date(pImpl->nTime.GetDate()))/86400 ; |
290 | 0 | tools::Time nAddTime(tools::Time::EMPTY); // Value to add on aOldTime |
291 | |
|
292 | 0 | if (nDays==0) |
293 | 0 | { |
294 | | // If no day between now and last editing - calculate time directly. |
295 | 0 | nAddTime = static_cast<const tools::Time&>(aNow) - static_cast<const tools::Time&>(pImpl->nTime); |
296 | 0 | } |
297 | 0 | else if (nDays<=31) |
298 | 0 | { |
299 | | // If time of working without save greater than 1 month (!)... |
300 | | // we add 0 to aOldTime! |
301 | | |
302 | | // If 1 or up to 31 days between now and last editing - calculate time indirectly. |
303 | | // nAddTime = (24h - nTime) + (nDays * 24h) + aNow |
304 | 0 | tools::Time n24Time (24,0,0,0); // Time-value for 24 hours |
305 | 0 | --nDays; |
306 | 0 | nAddTime.MakeTimeFromNS(nDays * n24Time.GetNSFromTime()); |
307 | 0 | nAddTime += n24Time-static_cast<const tools::Time&>(pImpl->nTime); |
308 | 0 | nAddTime += aNow ; |
309 | 0 | } |
310 | |
|
311 | 0 | lcl_add(editDuration, nAddTime); |
312 | 0 | } |
313 | |
|
314 | 0 | pImpl->nTime = aNow; |
315 | 0 | try { |
316 | 0 | const sal_Int32 newSecs( (editDuration.Hours*3600) |
317 | 0 | + (editDuration.Minutes*60) + editDuration.Seconds); |
318 | 0 | i_xDocProps->setEditingDuration(newSecs); |
319 | 0 | i_xDocProps->setEditingCycles(i_xDocProps->getEditingCycles() + 1); |
320 | 0 | } |
321 | 0 | catch (const lang::IllegalArgumentException &) |
322 | 0 | { |
323 | | // ignore overflow |
324 | 0 | } |
325 | 0 | } |
326 | | |
327 | | std::shared_ptr<SfxDocumentInfoDialog> SfxObjectShell::CreateDocumentInfoDialog(weld::Window* pParent, |
328 | | const SfxItemSet& rSet) |
329 | 0 | { |
330 | 0 | return std::make_shared<SfxDocumentInfoDialog>(pParent, rSet); |
331 | 0 | } |
332 | | |
333 | | std::optional<NamedColor> SfxObjectShell::GetRecentColor(sal_uInt16 nSlotId) |
334 | 0 | { |
335 | 0 | auto it = pImpl->m_aRecentColors.find(nSlotId); |
336 | 0 | if (it != pImpl->m_aRecentColors.end()) |
337 | 0 | return it->second; |
338 | | |
339 | 0 | return std::nullopt; |
340 | 0 | } |
341 | | |
342 | | void SfxObjectShell::SetRecentColor(sal_uInt16 nSlotId, const NamedColor& rColor, bool bBroadcast) |
343 | 0 | { |
344 | 0 | pImpl->m_aRecentColors[nSlotId] = rColor; |
345 | 0 | if (bBroadcast) |
346 | 0 | Broadcast(SfxHint(SfxHintId::ColorsChanged)); |
347 | 0 | } |
348 | | |
349 | | std::set<Color> SfxObjectShell::GetDocColors() |
350 | 0 | { |
351 | 0 | std::set<Color> empty; |
352 | 0 | return empty; |
353 | 0 | } |
354 | | |
355 | 0 | std::shared_ptr<model::ColorSet> SfxObjectShell::GetThemeColors() { return {}; } |
356 | | |
357 | | std::shared_ptr<sfx::IDocumentModelAccessor> SfxObjectShell::GetDocumentModelAccessor() const |
358 | 0 | { |
359 | 0 | return {}; |
360 | 0 | } |
361 | | |
362 | | sfx::AccessibilityIssueCollection SfxObjectShell::runAccessibilityCheck() |
363 | 0 | { |
364 | 0 | sfx::AccessibilityIssueCollection aCollection; |
365 | 0 | return aCollection; |
366 | 0 | } |
367 | | |
368 | | SfxStyleSheetBasePool* SfxObjectShell::GetStyleSheetPool() |
369 | 0 | { |
370 | 0 | return nullptr; |
371 | 0 | } |
372 | | |
373 | | namespace { |
374 | | |
375 | | struct Styles_Impl |
376 | | { |
377 | | SfxStyleSheetBase *pSource; |
378 | | SfxStyleSheetBase *pDest; |
379 | | }; |
380 | | |
381 | | } |
382 | | |
383 | | void SfxObjectShell::LoadStyles |
384 | | ( |
385 | | SfxObjectShell &rSource /* the document template from which |
386 | | the styles are to be loaded */ |
387 | | ) |
388 | | |
389 | | /* [Description] |
390 | | |
391 | | This method is called by the SFx if styles are to be loaded from a template. |
392 | | Existing styles are in this case overwritten. The document must then be |
393 | | re-formatted. Therefore, applications usually override this method |
394 | | and call the implementation in the base class. |
395 | | */ |
396 | | |
397 | 0 | { |
398 | 0 | SfxStyleSheetBasePool *pSourcePool = rSource.GetStyleSheetPool(); |
399 | 0 | DBG_ASSERT(pSourcePool, "Source-DocumentShell without StyleSheetPool"); |
400 | 0 | SfxStyleSheetBasePool *pMyPool = GetStyleSheetPool(); |
401 | 0 | DBG_ASSERT(pMyPool, "Dest-DocumentShell without StyleSheetPool"); |
402 | 0 | auto xIter = pSourcePool->CreateIterator(SfxStyleFamily::All); |
403 | 0 | std::unique_ptr<Styles_Impl[]> pFound(new Styles_Impl[xIter->Count()]); |
404 | 0 | sal_uInt16 nFound = 0; |
405 | |
|
406 | 0 | SfxStyleSheetBase *pSource = xIter->First(); |
407 | 0 | while ( pSource ) |
408 | 0 | { |
409 | 0 | SfxStyleSheetBase *pDest = |
410 | 0 | pMyPool->Find( pSource->GetName(), pSource->GetFamily() ); |
411 | 0 | if ( !pDest ) |
412 | 0 | { |
413 | 0 | pDest = &pMyPool->Make( pSource->GetName(), |
414 | 0 | pSource->GetFamily(), pSource->GetMask()); |
415 | | // Setting of parents, the next style |
416 | 0 | } |
417 | 0 | pFound[nFound].pSource = pSource; |
418 | 0 | pFound[nFound].pDest = pDest; |
419 | 0 | ++nFound; |
420 | 0 | pSource = xIter->Next(); |
421 | 0 | } |
422 | |
|
423 | 0 | for ( sal_uInt16 i = 0; i < nFound; ++i ) |
424 | 0 | { |
425 | 0 | pFound[i].pDest->GetItemSet().PutExtended(pFound[i].pSource->GetItemSet(), SfxItemState::INVALID, SfxItemState::DEFAULT); |
426 | 0 | if(pFound[i].pSource->HasParentSupport()) |
427 | 0 | pFound[i].pDest->SetParent(pFound[i].pSource->GetParent()); |
428 | 0 | if(pFound[i].pSource->HasFollowSupport()) |
429 | 0 | pFound[i].pDest->SetFollow(pFound[i].pSource->GetParent()); |
430 | 0 | } |
431 | 0 | } |
432 | | |
433 | | sfx2::StyleManager* SfxObjectShell::GetStyleManager() |
434 | 0 | { |
435 | 0 | return nullptr; |
436 | 0 | } |
437 | | |
438 | | namespace |
439 | | { |
440 | | class QueryTemplateBox |
441 | | { |
442 | | private: |
443 | | std::unique_ptr<weld::MessageDialog> m_xQueryBox; |
444 | | public: |
445 | | QueryTemplateBox(weld::Window* pParent, const OUString& rMessage) |
446 | 0 | : m_xQueryBox(Application::CreateMessageDialog(pParent, VclMessageType::Question, VclButtonsType::NONE, rMessage)) |
447 | 0 | { |
448 | 0 | m_xQueryBox->add_button(SfxResId(STR_QRYTEMPL_UPDATE_BTN), RET_YES); |
449 | 0 | m_xQueryBox->add_button(SfxResId(STR_QRYTEMPL_KEEP_BTN), RET_NO); |
450 | 0 | m_xQueryBox->set_default_response(RET_YES); |
451 | 0 | m_xQueryBox->set_help_id(HID_QUERY_LOAD_TEMPLATE); |
452 | 0 | } |
453 | 0 | short run() { return m_xQueryBox->run(); } |
454 | | }; |
455 | | } |
456 | | |
457 | | void SfxObjectShell::UpdateFromTemplate_Impl( ) |
458 | | |
459 | | /* [Description] |
460 | | |
461 | | This internal method checks whether the document was created from a |
462 | | template, and if this is newer than the document. If this is the case, |
463 | | the user is asked if the Templates (StyleSheets) should be updated. |
464 | | If this is answered positively, the StyleSheets are updated. |
465 | | */ |
466 | | |
467 | 4.26k | { |
468 | | // Storage-medium? |
469 | 4.26k | SfxMedium *pFile = GetMedium(); |
470 | 4.26k | DBG_ASSERT( pFile, "cannot UpdateFromTemplate without medium" ); |
471 | 4.26k | if ( !pFile ) |
472 | 0 | return; |
473 | | |
474 | 4.26k | if ( !comphelper::isFileUrl( pFile->GetName() ) ) |
475 | | // update only for documents loaded from the local file system |
476 | 4.26k | return; |
477 | | |
478 | | // tdf#113935 - do not remove this line - somehow, it makes the process |
479 | | // of switching from viewing a read-only document to opening it in writable |
480 | | // mode much faster. |
481 | 0 | uno::Reference< embed::XStorage > xDocStor = pFile->GetStorage(false); |
482 | | |
483 | | // only for own storage formats |
484 | 0 | if ( !pFile->GetFilter() || !pFile->GetFilter()->IsOwnFormat() ) |
485 | 0 | return; |
486 | | |
487 | 0 | const SfxUInt16Item* pUpdateDocItem = pFile->GetItemSet().GetItem(SID_UPDATEDOCMODE, false); |
488 | 0 | sal_Int16 bCanUpdateFromTemplate = pUpdateDocItem ? pUpdateDocItem->GetValue() : document::UpdateDocMode::NO_UPDATE; |
489 | | |
490 | | // created from template? |
491 | 0 | uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); |
492 | 0 | const OUString aTemplName( xDocProps->getTemplateName() ); |
493 | 0 | OUString aTemplURL( xDocProps->getTemplateURL() ); |
494 | 0 | OUString aFoundName; |
495 | |
|
496 | 0 | if ( !aTemplName.isEmpty() || (!aTemplURL.isEmpty() && !IsReadOnly()) ) |
497 | 0 | { |
498 | | // try to locate template, first using filename this must be done |
499 | | // because writer global document uses this "great" idea to manage |
500 | | // the templates of all parts in the master document but it is NOT |
501 | | // an error if the template filename points not to a valid file |
502 | 0 | SfxDocumentTemplates aTempl; |
503 | 0 | if (!aTemplURL.isEmpty()) |
504 | 0 | { |
505 | 0 | try { |
506 | 0 | aFoundName = ::rtl::Uri::convertRelToAbs(GetMedium()->GetName(), |
507 | 0 | aTemplURL); |
508 | 0 | } catch (::rtl::MalformedUriException const&) { |
509 | 0 | assert(false); // don't think that's supposed to happen? |
510 | 0 | } |
511 | 0 | } |
512 | |
|
513 | 0 | if( aFoundName.isEmpty() && !aTemplName.isEmpty() ) |
514 | | // if the template filename did not lead to success, |
515 | | // try to get a file name for the logical template name |
516 | 0 | aTempl.GetFull( u"", aTemplName, aFoundName ); |
517 | 0 | } |
518 | |
|
519 | 0 | if ( aFoundName.isEmpty() ) |
520 | 0 | return; |
521 | | |
522 | | // check existence of template storage |
523 | 0 | aTemplURL = aFoundName; |
524 | | |
525 | | // should the document checked against changes in the template ? |
526 | 0 | if ( !IsQueryLoadTemplate() ) |
527 | 0 | return; |
528 | | |
529 | 0 | bool bLoad = false; |
530 | | |
531 | | // load document properties of template |
532 | 0 | bool bOK = false; |
533 | 0 | util::DateTime aTemplDate; |
534 | 0 | try |
535 | 0 | { |
536 | 0 | Reference<document::XDocumentProperties> const |
537 | 0 | xTemplateDocProps( document::DocumentProperties::create( |
538 | 0 | ::comphelper::getProcessComponentContext())); |
539 | 0 | xTemplateDocProps->loadFromMedium(aTemplURL, |
540 | 0 | Sequence<beans::PropertyValue>()); |
541 | 0 | aTemplDate = xTemplateDocProps->getModificationDate(); |
542 | 0 | bOK = true; |
543 | 0 | } |
544 | 0 | catch (const Exception&) |
545 | 0 | { |
546 | 0 | TOOLS_INFO_EXCEPTION("sfx.doc", ""); |
547 | 0 | } |
548 | | |
549 | | // if modify date was read successfully |
550 | 0 | if ( bOK ) |
551 | 0 | { |
552 | | // compare modify data of template with the last check date of the document |
553 | 0 | const util::DateTime aInfoDate( xDocProps->getTemplateDate() ); |
554 | 0 | if ( aTemplDate > aInfoDate ) |
555 | 0 | { |
556 | | // ask user |
557 | 0 | if( bCanUpdateFromTemplate == document::UpdateDocMode::QUIET_UPDATE |
558 | 0 | || bCanUpdateFromTemplate == document::UpdateDocMode::FULL_UPDATE ) |
559 | 0 | bLoad = true; |
560 | 0 | else if ( bCanUpdateFromTemplate == document::UpdateDocMode::ACCORDING_TO_CONFIG ) |
561 | 0 | { |
562 | 0 | const OUString sMessage( SfxResId(STR_QRYTEMPL_MESSAGE).replaceAll( "$(ARG1)", aTemplName ) ); |
563 | 0 | QueryTemplateBox aBox(Application::GetFrameWeld(GetDialogParent()), sMessage); |
564 | 0 | if (RET_YES == aBox.run()) |
565 | 0 | bLoad = true; |
566 | 0 | } |
567 | |
|
568 | 0 | if( !bLoad ) |
569 | 0 | { |
570 | | // user refuses, so don't ask again for this document |
571 | 0 | SetQueryLoadTemplate(false); |
572 | 0 | SetModified(); |
573 | 0 | } |
574 | 0 | } |
575 | 0 | } |
576 | |
|
577 | 0 | if ( !bLoad ) |
578 | 0 | return; |
579 | | |
580 | | // styles should be updated, create document in organizer mode to read in the styles |
581 | | //TODO: testen! |
582 | 0 | SfxObjectShellLock xTemplDoc = CreateObjectByFactoryName( GetFactory().GetFactoryName(), SfxObjectCreateMode::ORGANIZER ); |
583 | 0 | xTemplDoc->DoInitNew(); |
584 | | |
585 | | // TODO/MBA: do we need a BaseURL? Then LoadFrom must be extended! |
586 | | //xTemplDoc->SetBaseURL( aFoundName ); |
587 | | |
588 | | // TODO/LATER: make sure that we don't use binary templates! |
589 | 0 | SfxMedium aMedium( aFoundName, StreamMode::STD_READ ); |
590 | 0 | if ( xTemplDoc->LoadFrom( aMedium ) ) |
591 | 0 | { |
592 | | // transfer styles from xTemplDoc to this document |
593 | | // TODO/MBA: make sure that no BaseURL is needed in *this* document |
594 | 0 | LoadStyles(*xTemplDoc); |
595 | | |
596 | | // remember date/time of check |
597 | 0 | xDocProps->setTemplateDate(aTemplDate); |
598 | | // TODO/LATER: new functionality to store document info is required ( didn't work for SO7 XML format ) |
599 | 0 | } |
600 | 0 | } |
601 | | |
602 | | bool SfxObjectShell::IsHelpDocument() const |
603 | 4.26k | { |
604 | 4.26k | if (!pMedium) |
605 | 0 | { |
606 | 0 | return false; |
607 | 0 | } |
608 | | |
609 | 4.26k | std::shared_ptr<const SfxFilter> pFilter = pMedium->GetFilter(); |
610 | 4.26k | return (pFilter && pFilter->GetFilterName() == "writer_web_HTML_help"); |
611 | 4.26k | } |
612 | | |
613 | | void SfxObjectShell::ResetFromTemplate( const OUString& rTemplateName, std::u16string_view rFileName ) |
614 | 0 | { |
615 | | // only care about resetting this data for LibreOffice formats otherwise |
616 | 0 | if ( !IsOwnStorageFormat( *GetMedium()) ) |
617 | 0 | return; |
618 | | |
619 | 0 | uno::Reference<document::XDocumentProperties> xDocProps(getDocProperties()); |
620 | 0 | xDocProps->setTemplateURL( OUString() ); |
621 | 0 | xDocProps->setTemplateName( OUString() ); |
622 | 0 | xDocProps->setTemplateDate( util::DateTime() ); |
623 | 0 | xDocProps->resetUserData( OUString() ); |
624 | | |
625 | | // TODO/REFACTOR: |
626 | | // Title? |
627 | |
|
628 | 0 | if( !comphelper::isFileUrl( rFileName ) ) |
629 | 0 | return; |
630 | | |
631 | 0 | OUString aFoundName; |
632 | 0 | if( SfxGetpApp()->Get_Impl()->GetDocumentTemplates()->GetFull( u"", rTemplateName, aFoundName ) ) |
633 | 0 | { |
634 | 0 | INetURLObject aObj( rFileName ); |
635 | 0 | xDocProps->setTemplateURL( aObj.GetMainURL(INetURLObject::DecodeMechanism::ToIUri) ); |
636 | 0 | xDocProps->setTemplateName( rTemplateName ); |
637 | |
|
638 | 0 | ::DateTime now( ::DateTime::SYSTEM ); |
639 | 0 | xDocProps->setTemplateDate( now.GetUNODateTime() ); |
640 | |
|
641 | 0 | SetQueryLoadTemplate( true ); |
642 | 0 | } |
643 | 0 | } |
644 | | |
645 | | bool SfxObjectShell::IsQueryLoadTemplate() const |
646 | 442 | { |
647 | 442 | return pImpl->bQueryLoadTemplate; |
648 | 442 | } |
649 | | |
650 | | bool SfxObjectShell::IsBasedOnTemplate() const |
651 | 0 | { |
652 | 0 | if (!pMedium) |
653 | 0 | return false; |
654 | 0 | const SfxBoolItem* pTemplateItem = pMedium->GetItemSet().GetItem(SID_TEMPLATE, false); |
655 | 0 | return pTemplateItem && pTemplateItem->GetValue(); |
656 | 0 | } |
657 | | |
658 | | bool SfxObjectShell::IsUseUserData() const |
659 | 707 | { |
660 | 707 | return pImpl->bUseUserData; |
661 | 707 | } |
662 | | |
663 | | bool SfxObjectShell::IsUseThumbnailSave() const |
664 | 3 | { |
665 | 3 | return pImpl->bUseThumbnailSave; |
666 | 3 | } |
667 | | |
668 | | void SfxObjectShell::SetQueryLoadTemplate( bool bNew ) |
669 | 1.45k | { |
670 | 1.45k | if ( pImpl->bQueryLoadTemplate != bNew ) |
671 | 181 | SetModified(); |
672 | 1.45k | pImpl->bQueryLoadTemplate = bNew; |
673 | 1.45k | } |
674 | | |
675 | | void SfxObjectShell::SetUseUserData( bool bNew ) |
676 | 2.14k | { |
677 | 2.14k | if ( pImpl->bUseUserData != bNew ) |
678 | 15 | SetModified(); |
679 | 2.14k | pImpl->bUseUserData = bNew; |
680 | 2.14k | } |
681 | | |
682 | | void SfxObjectShell::SetUseThumbnailSave( bool _bNew ) |
683 | 0 | { |
684 | 0 | if ( pImpl->bUseThumbnailSave != _bNew ) |
685 | 0 | SetModified(); |
686 | 0 | pImpl->bUseThumbnailSave = _bNew; |
687 | 0 | } |
688 | | |
689 | | bool SfxObjectShell::IsLoadReadonly() const |
690 | 523 | { |
691 | 523 | return pImpl->bLoadReadonly; |
692 | 523 | } |
693 | | |
694 | | bool SfxObjectShell::IsSaveVersionOnClose() const |
695 | 700 | { |
696 | 700 | return pImpl->bSaveVersionOnClose; |
697 | 700 | } |
698 | | |
699 | | void SfxObjectShell::SetLoadReadonly( bool bNew ) |
700 | 2.10k | { |
701 | 2.10k | if ( pImpl->bLoadReadonly != bNew ) |
702 | 26 | SetModified(); |
703 | 2.10k | pImpl->bLoadReadonly = bNew; |
704 | 2.10k | } |
705 | | |
706 | | void SfxObjectShell::SetSaveVersionOnClose( bool bNew ) |
707 | 2.16k | { |
708 | 2.16k | if ( pImpl->bSaveVersionOnClose != bNew ) |
709 | 5 | SetModified(); |
710 | 2.16k | pImpl->bSaveVersionOnClose = bNew; |
711 | 2.16k | } |
712 | | |
713 | | sal_uInt32 SfxObjectShell::GetModifyPasswordHash() const |
714 | 0 | { |
715 | 0 | return pImpl->m_nModifyPasswordHash; |
716 | 0 | } |
717 | | |
718 | | bool SfxObjectShell::SetModifyPasswordHash( sal_uInt32 nHash ) |
719 | 25.9k | { |
720 | 25.9k | if ( ( !IsReadOnly() && !IsReadOnlyUI() ) |
721 | 10.9k | || !(pImpl->nFlagsInProgress & SfxLoadedFlags::MAINDOCUMENT ) ) |
722 | 25.9k | { |
723 | | // the hash can be changed only in editable documents, |
724 | | // or during loading of document |
725 | 25.9k | pImpl->m_nModifyPasswordHash = nHash; |
726 | 25.9k | return true; |
727 | 25.9k | } |
728 | | |
729 | 0 | return false; |
730 | 25.9k | } |
731 | | |
732 | | const uno::Sequence< beans::PropertyValue >& SfxObjectShell::GetModifyPasswordInfo() const |
733 | 3 | { |
734 | 3 | return pImpl->m_aModifyPasswordInfo; |
735 | 3 | } |
736 | | |
737 | | bool SfxObjectShell::SetModifyPasswordInfo( const uno::Sequence< beans::PropertyValue >& aInfo ) |
738 | 0 | { |
739 | 0 | if ( ( !IsReadOnly() && !IsReadOnlyUI() ) |
740 | 0 | || !(pImpl->nFlagsInProgress & SfxLoadedFlags::MAINDOCUMENT ) ) |
741 | 0 | { |
742 | | // the hash can be changed only in editable documents, |
743 | | // or during loading of document |
744 | 0 | pImpl->m_aModifyPasswordInfo = aInfo; |
745 | 0 | return true; |
746 | 0 | } |
747 | | |
748 | 0 | return false; |
749 | 0 | } |
750 | | |
751 | | void SfxObjectShell::SetModifyPasswordEntered( bool bEntered ) |
752 | 0 | { |
753 | 0 | pImpl->m_bModifyPasswordEntered = bEntered; |
754 | 0 | } |
755 | | |
756 | | bool SfxObjectShell::IsModifyPasswordEntered() const |
757 | 0 | { |
758 | 0 | return pImpl->m_bModifyPasswordEntered; |
759 | 0 | } |
760 | | |
761 | | /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |