Coverage Report

Created: 2026-07-10 11:04

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/appl/sfxpicklist.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
#include <comphelper/lok.hxx>
21
#include <comphelper/base64.hxx>
22
#include <com/sun/star/document/XDocumentProperties.hpp>
23
#include <unotools/historyoptions.hxx>
24
#include <unotools/useroptions.hxx>
25
#include <tools/datetime.hxx>
26
#include <tools/stream.hxx>
27
#include <tools/urlobj.hxx>
28
#include <svl/inethist.hxx>
29
#include <svl/itemset.hxx>
30
#include <vcl/bitmap.hxx>
31
#include <vcl/filter/PngImageWriter.hxx>
32
#include <vcl/graph.hxx>
33
#include <vcl/svapp.hxx>
34
#include <officecfg/Office/Common.hxx>
35
36
37
#include <sfx2/app.hxx>
38
#include <sfxpicklist.hxx>
39
#include <sfx2/sfxsids.hrc>
40
#include <sfx2/event.hxx>
41
#include <sfx2/objsh.hxx>
42
#include <sfx2/docfile.hxx>
43
#include <openurlhint.hxx>
44
#include <sfx2/docfilt.hxx>
45
#include <sfx2/viewfrm.hxx>
46
47
48
using namespace ::com::sun::star::uno;
49
50
class SfxPickListImpl : public SfxListener
51
{
52
    /**
53
     * Adds the given document to the pick list (recent documents) if it satisfies
54
       certain requirements, e.g. being writable. Check implementation for requirement
55
       details.
56
     */
57
    static void AddDocumentToPickList(const SfxObjectShell* pDocShell, bool bNoThumbnail = false);
58
59
public:
60
    SfxPickListImpl(SfxApplication& rApp);
61
    virtual void Notify( SfxBroadcaster& rBC, const SfxHint& rHint ) override;
62
};
63
64
void SfxPickListImpl::AddDocumentToPickList(const SfxObjectShell* pDocSh, bool bNoThumbnail)
65
0
{
66
0
    if (pDocSh->IsAvoidRecentDocs() || comphelper::LibreOfficeKit::isActive())
67
0
        return;
68
69
0
    SfxMedium *pMed = pDocSh->GetMedium();
70
0
    if( !pMed )
71
0
        return;
72
73
    // Unnamed Documents and embedded-Documents not in Picklist
74
0
    if ( !pDocSh->HasName() ||
75
0
            SfxObjectCreateMode::STANDARD != pDocSh->GetCreateMode() )
76
0
        return;
77
78
    // Help not in History
79
0
    INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : pMed->GetOrigURL() );
80
0
    if ( aURL.GetProtocol() == INetProtocol::VndSunStarHelp )
81
0
        return;
82
83
    // add no document that forbids this
84
0
    if ( !pMed->IsUpdatePickList() )
85
0
        return;
86
87
    // ignore hidden documents
88
0
    if ( !SfxViewFrame::GetFirst( pDocSh ) )
89
0
        return;
90
91
0
    OUString  aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
92
0
    OUString  aFilter;
93
0
    std::shared_ptr<const SfxFilter> pFilter = pMed->GetFilter();
94
0
    if ( pFilter )
95
0
        aFilter = pFilter->GetFilterName();
96
97
0
    std::optional<OUString> aThumbnail;
98
99
    // generate the thumbnail
100
    //fdo#74834: only generate thumbnail for history if the corresponding option is not disabled in the configuration
101
0
    if (!bNoThumbnail && !pDocSh->IsModified() && !Application::IsHeadlessModeEnabled() &&
102
0
            officecfg::Office::Common::History::RecentDocsThumbnail::get())
103
0
    {
104
        // not modified => the document matches what is in the shell
105
0
        const SfxUnoAnyItem* pEncryptionDataItem = pMed->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
106
0
        if ( pEncryptionDataItem )
107
0
        {
108
            // encrypted document, will show a generic document icon instead
109
0
            aThumbnail = OUString();
110
0
        }
111
0
        else
112
0
        {
113
0
            Bitmap aResultBitmap = pDocSh->GetPreviewBitmap();
114
0
            if (!aResultBitmap.IsEmpty())
115
0
            {
116
0
                SvMemoryStream aStream(65535, 65535);
117
0
                vcl::PngImageWriter aWriter(aStream);
118
0
                if (aWriter.write(aResultBitmap))
119
0
                {
120
0
                    Sequence<sal_Int8> aSequence(static_cast<const sal_Int8*>(aStream.GetData()), aStream.Tell());
121
0
                    OUStringBuffer aBuffer;
122
0
                    ::comphelper::Base64::encode(aBuffer, aSequence);
123
0
                    aThumbnail = aBuffer.makeStringAndClear();
124
0
                }
125
0
            }
126
0
        }
127
0
    }
128
0
    ::std::optional<bool> const oIsReadOnly(pMed->IsOriginallyLoadedReadOnly());
129
130
    // add to svtool history options
131
0
    SvtHistoryOptions::AppendItem( EHistoryType::PickList,
132
0
            aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
133
0
            aFilter,
134
0
            aTitle,
135
0
            aThumbnail,
136
0
            oIsReadOnly);
137
138
0
    if ( aURL.GetProtocol() == INetProtocol::File )
139
0
        Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::DecodeMechanism::NONE ),
140
0
                                                                 pFilter ? pFilter->GetMimeType() : OUString(),
141
0
                                                                 pFilter ? pFilter->GetServiceName() : OUString() );
142
0
}
143
144
SfxPickList::SfxPickList(SfxApplication& rApp)
145
0
    : mxImpl(new SfxPickListImpl(rApp))
146
0
{
147
0
}
148
149
SfxPickList::~SfxPickList()
150
0
{
151
0
}
152
153
SfxPickListImpl::SfxPickListImpl(SfxApplication& rApp)
154
0
{
155
0
    StartListening(rApp);
156
0
}
157
158
void SfxPickListImpl::Notify( SfxBroadcaster&, const SfxHint& rHint )
159
0
{
160
0
    if (rHint.GetId() == SfxHintId::SfxOpenUrl)
161
0
    {
162
0
        const SfxOpenUrlHint* pOpenUrlHint = static_cast<const SfxOpenUrlHint*>(&rHint);
163
0
        INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pOpenUrlHint->GetDocumentURL() ));
164
0
    }
165
166
0
    if (rHint.GetId() != SfxHintId::ThisIsAnSfxEventHint)
167
0
        return;
168
169
0
    const SfxEventHint& rEventHint = static_cast<const SfxEventHint&>(rHint);
170
    // only ObjectShell-related events with media interest
171
0
    rtl::Reference<SfxObjectShell> pDocSh = rEventHint.GetObjShell();
172
0
    if( !pDocSh )
173
0
        return;
174
175
0
    switch (rEventHint.GetEventId())
176
0
    {
177
0
        case SfxEventHintId::CreateDoc:
178
0
        {
179
0
            bool bAllowModif = pDocSh->IsEnableSetModified();
180
0
            if ( bAllowModif )
181
0
                pDocSh->EnableSetModified( false );
182
183
0
            using namespace ::com::sun::star;
184
0
            uno::Reference<document::XDocumentProperties> xDocProps(
185
0
                pDocSh->getDocProperties());
186
0
            if (xDocProps.is()) {
187
0
                xDocProps->setAuthor( SvtUserOptions().GetFullName() );
188
0
                ::DateTime now( ::DateTime::SYSTEM );
189
0
                xDocProps->setCreationDate( now.GetUNODateTime() );
190
0
            }
191
192
0
            if ( bAllowModif )
193
0
                pDocSh->EnableSetModified( bAllowModif );
194
0
        }
195
0
        break;
196
197
0
        case SfxEventHintId::OpenDoc:
198
0
        case SfxEventHintId::SaveDocDone:
199
0
        case SfxEventHintId::SaveAsDocDone:
200
0
        case SfxEventHintId::SaveToDocDone:
201
0
        case SfxEventHintId::CloseDoc:
202
0
        {
203
0
            const bool bNoThumbnail = rEventHint.GetEventId() == SfxEventHintId::CloseDoc;
204
0
            AddDocumentToPickList(pDocSh.get(), bNoThumbnail);
205
0
        }
206
0
        break;
207
208
0
        case SfxEventHintId::SaveAsDoc:
209
0
        {
210
0
            SfxMedium *pMedium = pDocSh->GetMedium();
211
0
            if (!pMedium)
212
0
                return;
213
214
            // We're starting a "Save As". Add the current document (if it's
215
            // not a "new" document) to the "Recent Documents" list before we
216
            // switch to the new path.
217
            // If the current document is new, path will be empty.
218
0
            OUString path = pMedium->GetOrigURL();
219
0
            if (!path.isEmpty())
220
0
            {
221
0
                AddDocumentToPickList(pDocSh.get());
222
0
            }
223
0
        }
224
0
        break;
225
0
        default: break;
226
0
    }
227
0
}
228
229
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */