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