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 .
21 #include <com/sun/star/uno/Reference.hxx>
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 <com/sun/star/frame/XLayoutManager.hpp>
27 #include <com/sun/star/embed/ElementModes.hpp>
28 #include <vcl/msgbox.hxx>
29 #include <svl/style.hxx>
30 #include <vcl/wrkwin.hxx>
32 #include <svl/stritem.hxx>
33 #include <svl/intitem.hxx>
34 #include <svl/rectitem.hxx>
35 #include <svl/eitem.hxx>
36 #include <svl/urihelper.hxx>
37 #include <svl/ctloptions.hxx>
38 #include <comphelper/storagehelper.hxx>
39 #include <comphelper/processfactory.hxx>
40 #include <unotools/securityoptions.hxx>
41 #include <svtools/sfxecode.hxx>
42 #include <svtools/ehdl.hxx>
43 #include <tools/datetime.hxx>
44 #include <rtl/uri.hxx>
47 #include <unotools/saveopt.hxx>
48 #include <unotools/useroptions.hxx>
49 #include <unotools/localfilehelper.hxx>
50 #include <vcl/virdev.hxx>
51 #include <vcl/oldprintadaptor.hxx>
52 #include <vcl/settings.hxx>
54 #include <sfx2/app.hxx>
55 #include <sfx2/sfxresid.hxx>
56 #include "appdata.hxx"
57 #include <sfx2/dinfdlg.hxx>
58 #include <sfx2/fcontnr.hxx>
59 #include <sfx2/docfac.hxx>
60 #include <sfx2/viewsh.hxx>
61 #include <sfx2/objsh.hxx>
62 #include "objshimp.hxx"
63 #include <sfx2/evntconf.hxx>
64 #include <sfx2/sfxhelp.hxx>
65 #include <sfx2/dispatch.hxx>
66 #include <sfx2/printer.hxx>
67 #include <basic/basmgr.hxx>
68 #include <svtools/svtools.hrc>
69 #include <sfx2/viewfrm.hxx>
70 #include <sfx2/doctempl.hxx>
72 #include <sfx2/sfxbasemodel.hxx>
73 #include <sfx2/docfile.hxx>
74 #include <sfx2/request.hxx>
75 #include "openflag.hxx"
76 #include "querytemplate.hxx"
77 #include <boost/scoped_array.hpp>
79 #include <LibreOfficeKit/LibreOfficeKitTypes.h>
83 using namespace ::com::sun::star
;
84 using namespace ::com::sun::star::uno
;
89 bool operator> (const util::DateTime
& i_rLeft
, const util::DateTime
& i_rRight
)
91 if ( i_rLeft
.Year
!= i_rRight
.Year
)
92 return i_rLeft
.Year
> i_rRight
.Year
;
94 if ( i_rLeft
.Month
!= i_rRight
.Month
)
95 return i_rLeft
.Month
> i_rRight
.Month
;
97 if ( i_rLeft
.Day
!= i_rRight
.Day
)
98 return i_rLeft
.Day
> i_rRight
.Day
;
100 if ( i_rLeft
.Hours
!= i_rRight
.Hours
)
101 return i_rLeft
.Hours
> i_rRight
.Hours
;
103 if ( i_rLeft
.Minutes
!= i_rRight
.Minutes
)
104 return i_rLeft
.Minutes
> i_rRight
.Minutes
;
106 if ( i_rLeft
.Seconds
!= i_rRight
.Seconds
)
107 return i_rLeft
.Seconds
> i_rRight
.Seconds
;
109 if ( i_rLeft
.NanoSeconds
!= i_rRight
.NanoSeconds
)
110 return i_rLeft
.NanoSeconds
> i_rRight
.NanoSeconds
;
115 std::shared_ptr
<GDIMetaFile
>
116 SfxObjectShell::GetPreviewMetaFile( bool bFullContent
) const
118 return CreatePreviewMetaFile_Impl( bFullContent
);
121 std::shared_ptr
<GDIMetaFile
>
122 SfxObjectShell::CreatePreviewMetaFile_Impl( bool bFullContent
) const
124 // DoDraw can only be called when no printing is done, otherwise
125 // the printer may be turned off
126 SfxViewFrame
*pFrame
= SfxViewFrame::GetFirst( this );
127 if ( pFrame
&& pFrame
->GetViewShell() &&
128 pFrame
->GetViewShell()->GetPrinter() &&
129 pFrame
->GetViewShell()->GetPrinter()->IsPrinting() )
130 return std::shared_ptr
<GDIMetaFile
>();
132 std::shared_ptr
<GDIMetaFile
> xFile(new GDIMetaFile
);
134 ScopedVclPtrInstance
< VirtualDevice
> pDevice
;
135 pDevice
->EnableOutput( false );
137 MapMode
aMode( this->GetMapUnit() );
138 pDevice
->SetMapMode( aMode
);
139 xFile
->SetPrefMapMode( aMode
);
145 nAspect
= ASPECT_CONTENT
;
146 aTmpSize
= GetVisArea( nAspect
).GetSize();
150 nAspect
= ASPECT_THUMBNAIL
;
151 aTmpSize
= const_cast<SfxObjectShell
*>(this)->GetFirstPageSize();
154 xFile
->SetPrefSize( aTmpSize
);
155 DBG_ASSERT( aTmpSize
.Height()*aTmpSize
.Width(),
156 "size of first page is 0, override GetFirstPageSize or set vis-area!" );
158 xFile
->Record( pDevice
);
161 SvtCTLOptions aCTLOptions
;
162 if ( SvtCTLOptions::NUMERALS_HINDI
== aCTLOptions
.GetCTLTextNumerals() )
163 eLang
= LANGUAGE_ARABIC_SAUDI_ARABIA
;
164 else if ( SvtCTLOptions::NUMERALS_ARABIC
== aCTLOptions
.GetCTLTextNumerals() )
165 eLang
= LANGUAGE_ENGLISH
;
167 eLang
= (LanguageType
) Application::GetSettings().GetLanguageTag().getLanguageType();
169 pDevice
->SetDigitLanguage( eLang
);
171 const_cast<SfxObjectShell
*>(this)->DoDraw( pDevice
, Point(0,0), aTmpSize
, JobSetup(), nAspect
);
180 void SfxObjectShell::UpdateDocInfoForSave()
182 uno::Reference
<document::XDocumentProperties
> xDocProps(getDocProperties());
184 // clear user data if recommend (see 'Tools - Options - Open/StarOffice - Security')
185 if ( SvtSecurityOptions().IsOptionSet(
186 SvtSecurityOptions::E_DOCWARN_REMOVEPERSONALINFO
) )
188 xDocProps
->resetUserData( OUString() );
190 else if ( IsModified() )
192 OUString aUserName
= SvtUserOptions().GetFullName();
193 if ( !IsUseUserData() )
195 // remove all data pointing to the current user
196 if (xDocProps
->getAuthor().equals(aUserName
)) {
197 xDocProps
->setAuthor( OUString() );
199 xDocProps
->setModifiedBy( OUString() );
200 if (xDocProps
->getPrintedBy().equals(aUserName
)) {
201 xDocProps
->setPrintedBy( OUString() );
206 // update ModificationAuthor, revision and editing time
207 ::DateTime
now( ::DateTime::SYSTEM
);
208 xDocProps
->setModificationDate( now
.GetUNODateTime() );
209 xDocProps
->setModifiedBy( aUserName
);
210 UpdateTime_Impl( xDocProps
);
218 lcl_add(util::Duration
& rDur
, tools::Time
const& rTime
)
220 // here we don't care about overflow: rDur is converted back to seconds
221 // anyway, and tools::Time cannot store more than ~4000 hours
222 rDur
.Hours
+= rTime
.GetHour();
223 rDur
.Minutes
+= rTime
.GetMin();
224 rDur
.Seconds
+= rTime
.GetSec();
227 // Update the processing time
228 void SfxObjectShell::UpdateTime_Impl(
229 const uno::Reference
<document::XDocumentProperties
> & i_xDocProps
)
231 // Get old time from documentinfo
232 const sal_Int32 secs
= i_xDocProps
->getEditingDuration();
233 util::Duration
editDuration(sal_False
, 0, 0, 0,
234 secs
/3600, (secs
%3600)/60, secs
%60, 0);
236 // Initialize some local member! Its necessary for wollow operations!
237 DateTime
aNow( DateTime::SYSTEM
); // Date and time at current moment
238 tools::Time
n24Time (24,0,0,0) ; // Time-value for 24 hours - see follow calculation
239 sal_uIntPtr nDays
= 0 ; // Count of days between now and last editing
240 tools::Time
nAddTime (0) ; // Value to add on aOldTime
242 // Safe impossible cases!
243 // User has changed time to the past between last editing and now ... its not possible!!!
244 DBG_ASSERT( !(aNow
.GetDate()<pImp
->nTime
.GetDate()), "Timestamp of last change is in the past ?!..." );
246 // Do the follow only, if user has NOT changed time to the past.
247 // Else add a time of 0 to aOldTime ... !!!
248 if (aNow
.GetDate()>=pImp
->nTime
.GetDate())
250 // Get count of days last editing.
251 nDays
= aNow
.GetSecFromDateTime(pImp
->nTime
.GetDate())/86400 ;
255 // If no day between now and last editing - calculate time directly.
256 nAddTime
= (const tools::Time
&)aNow
- (const tools::Time
&)pImp
->nTime
;
260 // If time of working without save greater then 1 month (!) ....
261 // we add 0 to aOldTime!
263 // If 1 or up to 31 days between now and last editing - calculate time indirectly.
264 // nAddTime = (24h - nTime) + (nDays * 24h) + aNow
266 nAddTime
= nDays
*n24Time
.GetTime() ;
267 nAddTime
+= n24Time
-(const tools::Time
&)pImp
->nTime
;
271 lcl_add(editDuration
, nAddTime
);
276 const sal_Int32
newSecs( (editDuration
.Hours
*3600)
277 + (editDuration
.Minutes
*60) + editDuration
.Seconds
);
278 i_xDocProps
->setEditingDuration(newSecs
);
279 i_xDocProps
->setEditingCycles(i_xDocProps
->getEditingCycles() + 1);
281 catch (const lang::IllegalArgumentException
&)
289 VclPtr
<SfxDocumentInfoDialog
> SfxObjectShell::CreateDocumentInfoDialog
291 vcl::Window
* pParent
,
292 const SfxItemSet
& rSet
295 return VclPtr
<SfxDocumentInfoDialog
>::Create(pParent
, rSet
);
301 std::set
<Color
> SfxObjectShell::GetDocColors()
303 std::set
<Color
> empty
;
307 SfxStyleSheetBasePool
* SfxObjectShell::GetStyleSheetPool()
314 SfxStyleSheetBase
*pSource
;
315 SfxStyleSheetBase
*pDest
;
318 void SfxObjectShell::LoadStyles
320 SfxObjectShell
&rSource
/* the document template from which
321 the styles are to be loaded */
326 This method is called by the SFx if styles are to be loaded from a template.
327 Existing styles are in this case overwritten. The document must then be
328 re-formatted. Therefore, applications usually override this method
329 and call the implementation in the base class.
333 SfxStyleSheetBasePool
*pSourcePool
= rSource
.GetStyleSheetPool();
334 DBG_ASSERT(pSourcePool
, "Source-DocumentShell ohne StyleSheetPool");
335 SfxStyleSheetBasePool
*pMyPool
= GetStyleSheetPool();
336 DBG_ASSERT(pMyPool
, "Dest-DocumentShell ohne StyleSheetPool");
337 pSourcePool
->SetSearchMask(SFX_STYLE_FAMILY_ALL
, SFXSTYLEBIT_ALL
);
338 boost::scoped_array
<Styles_Impl
> pFound(new Styles_Impl
[pSourcePool
->Count()]);
339 sal_uInt16 nFound
= 0;
341 SfxStyleSheetBase
*pSource
= pSourcePool
->First();
344 SfxStyleSheetBase
*pDest
=
345 pMyPool
->Find( pSource
->GetName(), pSource
->GetFamily() );
348 pDest
= &pMyPool
->Make( pSource
->GetName(),
349 pSource
->GetFamily(), pSource
->GetMask());
350 // Setting of Parents, the next style
352 pFound
[nFound
].pSource
= pSource
;
353 pFound
[nFound
].pDest
= pDest
;
355 pSource
= pSourcePool
->Next();
358 for ( sal_uInt16 i
= 0; i
< nFound
; ++i
)
360 pFound
[i
].pDest
->GetItemSet().PutExtended(pFound
[i
].pSource
->GetItemSet(), SfxItemState::DONTCARE
, SfxItemState::DEFAULT
);
361 if(pFound
[i
].pSource
->HasParentSupport())
362 pFound
[i
].pDest
->SetParent(pFound
[i
].pSource
->GetParent());
363 if(pFound
[i
].pSource
->HasFollowSupport())
364 pFound
[i
].pDest
->SetFollow(pFound
[i
].pSource
->GetParent());
368 sfx2::StyleManager
* SfxObjectShell::GetStyleManager()
373 void SfxObjectShell::UpdateFromTemplate_Impl( )
377 This internal method checks whether the document was created from a
378 template, and if this is newer than the document. If this is the case,
379 the user is asked if the Templates (StyleSheets) should be updated.
380 If this is answered positively, the StyleSheets are updated.
385 SfxMedium
*pFile
= GetMedium();
386 DBG_ASSERT( pFile
, "cannot UpdateFromTemplate without medium" );
390 if ( !::utl::LocalFileHelper::IsLocalFile( pFile
->GetName() ) )
391 // update only for documents loaded from the local file system
394 // only for own storage formats
395 uno::Reference
< embed::XStorage
> xDocStor
= pFile
->GetStorage();
396 if ( !pFile
->GetFilter() || !pFile
->GetFilter()->IsOwnFormat() )
399 SFX_ITEMSET_ARG( pFile
->GetItemSet(), pUpdateDocItem
, SfxUInt16Item
, SID_UPDATEDOCMODE
, false);
400 sal_Int16 bCanUpdateFromTemplate
= pUpdateDocItem
? pUpdateDocItem
->GetValue() : document::UpdateDocMode::NO_UPDATE
;
402 // created from template?
403 uno::Reference
<document::XDocumentProperties
> xDocProps(getDocProperties());
404 OUString
aTemplName( xDocProps
->getTemplateName() );
405 OUString
aTemplURL( xDocProps
->getTemplateURL() );
408 if ( !aTemplName
.isEmpty() || (!aTemplURL
.isEmpty() && !IsReadOnly()) )
410 // try to locate template, first using filename this must be done
411 // because writer global document uses this "great" idea to manage
412 // the templates of all parts in the master document but it is NOT
413 // an error if the template filename points not to a valid file
414 SfxDocumentTemplates aTempl
;
415 if (!aTemplURL
.isEmpty())
418 aFoundName
= ::rtl::Uri::convertRelToAbs(GetMedium()->GetName(),
420 } catch (::rtl::MalformedUriException
const&) {
421 assert(false); // don't think that's supposed to happen?
425 if( aFoundName
.isEmpty() && !aTemplName
.isEmpty() )
426 // if the template filename did not lead to success,
427 // try to get a file name for the logical template name
428 aTempl
.GetFull( OUString(), aTemplName
, aFoundName
);
431 if ( !aFoundName
.isEmpty() )
433 // check existence of template storage
434 aTemplURL
= aFoundName
;
436 // should the document checked against changes in the template ?
437 if ( IsQueryLoadTemplate() )
441 // load document properties of template
443 util::DateTime aTemplDate
;
446 Reference
<document::XDocumentProperties
> const
447 xTemplateDocProps( document::DocumentProperties::create(
448 ::comphelper::getProcessComponentContext()));
449 xTemplateDocProps
->loadFromMedium(aTemplURL
,
450 Sequence
<beans::PropertyValue
>());
451 aTemplDate
= xTemplateDocProps
->getModificationDate();
454 catch (const Exception
& e
)
456 SAL_INFO("sfx.doc", "caught exception" << e
.Message
);
459 // if modify date was read successfully
462 // compare modify data of template with the last check date of the document
463 const util::DateTime
aInfoDate( xDocProps
->getTemplateDate() );
464 if ( aTemplDate
> aInfoDate
)
467 if( bCanUpdateFromTemplate
== document::UpdateDocMode::QUIET_UPDATE
468 || bCanUpdateFromTemplate
== document::UpdateDocMode::FULL_UPDATE
)
470 else if ( bCanUpdateFromTemplate
== document::UpdateDocMode::ACCORDING_TO_CONFIG
)
472 OUString
sMessage( SfxResId(STR_QRYTEMPL_MESSAGE
).toString() );
473 sMessage
= sMessage
.replaceAll( "$(ARG1)", aTemplName
);
474 ScopedVclPtrInstance
< sfx2::QueryTemplateBox
> aBox(GetDialogParent(), sMessage
);
475 if ( RET_YES
== aBox
->Execute() )
481 // user refuses, so don't ask again for this document
482 SetQueryLoadTemplate(false);
490 // styles should be updated, create document in organizer mode to read in the styles
492 SfxObjectShellLock xTemplDoc
= CreateObjectByFactoryName( GetFactory().GetFactoryName(), SfxObjectCreateMode::ORGANIZER
);
493 xTemplDoc
->DoInitNew(0);
495 // TODO/MBA: do we need a BaseURL? Then LoadFrom must be extended!
496 //xTemplDoc->SetBaseURL( aFoundName );
498 // TODO/LATER: make sure that we don't use binary templates!
499 SfxMedium
aMedium( aFoundName
, STREAM_STD_READ
);
500 if ( xTemplDoc
->LoadFrom( aMedium
) )
502 // transfer styles from xTemplDoc to this document
503 // TODO/MBA: make sure that no BaseURL is needed in *this* document
504 LoadStyles(*xTemplDoc
);
506 // remember date/time of check
507 xDocProps
->setTemplateDate(aTemplDate
);
508 // TODO/LATER: new functionality to store document info is required ( didn't work for SO7 XML format )
515 bool SfxObjectShell::IsHelpDocument() const
517 const SfxFilter
* pFilter
= GetMedium()->GetFilter();
518 return (pFilter
&& pFilter
->GetFilterName() == "writer_web_HTML_help");
521 void SfxObjectShell::ResetFromTemplate( const OUString
& rTemplateName
, const OUString
& rFileName
)
523 // only care about reseting this data for openoffice formats otherwise
524 if ( IsOwnStorageFormat_Impl( *GetMedium()) )
526 uno::Reference
<document::XDocumentProperties
> xDocProps(getDocProperties());
527 xDocProps
->setTemplateURL( OUString() );
528 xDocProps
->setTemplateName( OUString() );
529 xDocProps
->setTemplateDate( util::DateTime() );
530 xDocProps
->resetUserData( OUString() );
535 if( ::utl::LocalFileHelper::IsLocalFile( rFileName
) )
538 if( SfxGetpApp()->Get_Impl()->GetDocumentTemplates()->GetFull( OUString(), rTemplateName
, aFoundName
) )
540 INetURLObject
aObj( rFileName
);
541 xDocProps
->setTemplateURL( aObj
.GetMainURL(INetURLObject::DECODE_TO_IURI
) );
542 xDocProps
->setTemplateName( rTemplateName
);
544 ::DateTime
now( ::DateTime::SYSTEM
);
545 xDocProps
->setTemplateDate( now
.GetUNODateTime() );
547 SetQueryLoadTemplate( true );
553 bool SfxObjectShell::IsQueryLoadTemplate() const
555 return pImp
->bQueryLoadTemplate
;
558 bool SfxObjectShell::IsUseUserData() const
560 return pImp
->bUseUserData
;
563 void SfxObjectShell::SetQueryLoadTemplate( bool bNew
)
565 if ( pImp
->bQueryLoadTemplate
!= bNew
)
567 pImp
->bQueryLoadTemplate
= bNew
;
570 void SfxObjectShell::SetUseUserData( bool bNew
)
572 if ( pImp
->bUseUserData
!= bNew
)
574 pImp
->bUseUserData
= bNew
;
577 bool SfxObjectShell::IsLoadReadonly() const
579 return pImp
->bLoadReadonly
;
582 bool SfxObjectShell::IsSaveVersionOnClose() const
584 return pImp
->bSaveVersionOnClose
;
587 void SfxObjectShell::SetLoadReadonly( bool bNew
)
589 if ( pImp
->bLoadReadonly
!= bNew
)
591 pImp
->bLoadReadonly
= bNew
;
594 void SfxObjectShell::SetSaveVersionOnClose( bool bNew
)
596 if ( pImp
->bSaveVersionOnClose
!= bNew
)
598 pImp
->bSaveVersionOnClose
= bNew
;
601 sal_uInt32
SfxObjectShell::GetModifyPasswordHash() const
603 return pImp
->m_nModifyPasswordHash
;
606 bool SfxObjectShell::SetModifyPasswordHash( sal_uInt32 nHash
)
608 if ( ( !IsReadOnly() && !IsReadOnlyUI() )
609 || !(pImp
->nFlagsInProgress
& SfxLoadedFlags::MAINDOCUMENT
) )
611 // the hash can be changed only in editable documents,
612 // or during loading of document
613 pImp
->m_nModifyPasswordHash
= nHash
;
620 uno::Sequence
< beans::PropertyValue
> SfxObjectShell::GetModifyPasswordInfo() const
622 return pImp
->m_aModifyPasswordInfo
;
625 bool SfxObjectShell::SetModifyPasswordInfo( const uno::Sequence
< beans::PropertyValue
>& aInfo
)
627 if ( ( !IsReadOnly() && !IsReadOnlyUI() )
628 || !(pImp
->nFlagsInProgress
& SfxLoadedFlags::MAINDOCUMENT
) )
630 // the hash can be changed only in editable documents,
631 // or during loading of document
632 pImp
->m_aModifyPasswordInfo
= aInfo
;
639 void SfxObjectShell::SetModifyPasswordEntered( bool bEntered
)
641 pImp
->m_bModifyPasswordEntered
= bEntered
;
644 bool SfxObjectShell::IsModifyPasswordEntered()
646 return pImp
->m_bModifyPasswordEntered
;
649 void SfxObjectShell::libreOfficeKitCallback(int /*nType*/, const char* /*pPayload*/) const
651 SAL_INFO("tiled-rendering", "SfxObjectShell::libreOfficeKitCallback interface not overridden for SfxObjectShell subclass typeId: " << typeid(*this).name());
654 bool SfxObjectShell::isTiledRendering() const
656 SAL_INFO("tiled-rendering", "SfxObjectShell::isTiledRendering interface not overridden for SfxObjectShell subclass typeId: " << typeid(*this).name());
660 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */