Coverage Report

Created: 2025-12-08 09:28

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/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: */