Line data Source code
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/document/XDocumentProperties.hpp>
22 : #include <unotools/historyoptions.hxx>
23 : #include <unotools/useroptions.hxx>
24 : #include <tools/urlobj.hxx>
25 : #include <framework/menuconfiguration.hxx>
26 : #include <svl/inethist.hxx>
27 : #include <svl/stritem.hxx>
28 : #include <svl/eitem.hxx>
29 : #include <osl/file.hxx>
30 : #include <unotools/localfilehelper.hxx>
31 : #include <cppuhelper/implbase1.hxx>
32 :
33 : // ----------------------------------------------------------------------------
34 :
35 : #include <sfx2/app.hxx>
36 : #include "sfxpicklist.hxx"
37 : #include <sfx2/sfxuno.hxx>
38 : #include "sfxtypes.hxx"
39 : #include <sfx2/request.hxx>
40 : #include <sfx2/sfxsids.hrc>
41 : #include <sfx2/sfx.hrc>
42 : #include <sfx2/event.hxx>
43 : #include <sfx2/objsh.hxx>
44 : #include <sfx2/bindings.hxx>
45 : #include "referers.hxx"
46 : #include <sfx2/docfile.hxx>
47 : #include "objshimp.hxx"
48 : #include <sfx2/docfilt.hxx>
49 :
50 : #include <rtl/instance.hxx>
51 :
52 : #include <algorithm>
53 :
54 : // ----------------------------------------------------------------------------
55 :
56 : using namespace ::com::sun::star::uno;
57 : using namespace ::com::sun::star::beans;
58 : using namespace ::com::sun::star::util;
59 :
60 : // ----------------------------------------------------------------------------
61 :
62 : class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
63 : {
64 : public:
65 19 : StringLength() {}
66 38 : virtual ~StringLength() {}
67 :
68 : // XStringWidth
69 0 : sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
70 : throw (::com::sun::star::uno::RuntimeException)
71 : {
72 0 : return aString.getLength();
73 : }
74 : };
75 :
76 0 : void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const ::rtl::OUString& aURLString, sal_uInt32 nNo )
77 : {
78 0 : ::rtl::OUStringBuffer aPickEntry;
79 :
80 0 : if ( nNo < 9 )
81 : {
82 0 : aPickEntry.append('~');
83 0 : aPickEntry.append(::rtl::OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
84 : }
85 0 : else if ( nNo == 9 )
86 0 : aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("1~0"));
87 : else
88 0 : aPickEntry.append(::rtl::OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
89 0 : aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
90 :
91 0 : INetURLObject aURL( aURLString );
92 0 : rtl::OUString aTipHelpText;
93 0 : rtl::OUString aAccessibleName = aPickEntry.toString();
94 :
95 0 : if ( aURL.GetProtocol() == INET_PROT_FILE )
96 : {
97 : // Do handle file URL differently => convert it to a system
98 : // path and abbreviate it with a special function:
99 0 : ::rtl::OUString aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
100 :
101 0 : ::rtl::OUString aSystemPath( aFileSystemPath );
102 0 : ::rtl::OUString aCompactedSystemPath;
103 :
104 0 : aTipHelpText = aSystemPath;
105 0 : aAccessibleName += aSystemPath;
106 0 : oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
107 0 : if ( !nError )
108 0 : aPickEntry.append( aCompactedSystemPath );
109 : else
110 0 : aPickEntry.append( aFileSystemPath );
111 :
112 0 : if ( aPickEntry.getLength() > 50 )
113 : {
114 0 : aPickEntry.setLength( 47 );
115 0 : aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
116 0 : }
117 : }
118 : else
119 : {
120 : // Use INetURLObject to abbreviate all other URLs
121 0 : ::rtl::OUString aShortURL;
122 0 : aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
123 0 : aPickEntry.append(aShortURL);
124 0 : aTipHelpText = aURLString;
125 0 : aAccessibleName += aURLString;
126 : }
127 :
128 : // Set menu item text, tip help and accessible name
129 0 : pMenu->SetItemText( nItemId, aPickEntry.toString() );
130 0 : pMenu->SetTipHelpText( nItemId, aTipHelpText );
131 0 : pMenu->SetAccessibleName( nItemId, aAccessibleName );
132 0 : }
133 :
134 : namespace
135 : {
136 : class thePickListMutex
137 : : public rtl::Static<osl::Mutex, thePickListMutex> {};
138 : }
139 :
140 19 : void SfxPickList::RemovePickListEntries()
141 : {
142 19 : ::osl::MutexGuard aGuard( thePickListMutex::get() );
143 19 : for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
144 0 : delete m_aPicklistVector[i];
145 19 : m_aPicklistVector.clear();
146 19 : }
147 :
148 0 : SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
149 : {
150 : OSL_ASSERT( m_aPicklistVector.size() > nIndex );
151 :
152 0 : if ( nIndex < m_aPicklistVector.size() )
153 0 : return m_aPicklistVector[ nIndex ];
154 : else
155 0 : return 0;
156 : }
157 :
158 118 : void SfxPickList::AddDocumentToPickList( SfxObjectShell* pDocSh )
159 : {
160 118 : SfxMedium *pMed = pDocSh->GetMedium();
161 118 : if( !pMed )
162 : return;
163 :
164 : // Unnamed Documents and embedded-Documents not in Picklist
165 236 : if ( !pDocSh->HasName() ||
166 118 : SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
167 : return;
168 :
169 : // Help not in History
170 118 : INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
171 118 : if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
172 : return;
173 :
174 118 : if ( !pMed->IsUpdatePickList() )
175 : return;
176 :
177 : // add no document that forbids this (for example Message-Body)
178 118 : SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
179 118 : if ( pPicklistItem && !pPicklistItem->GetValue() )
180 : return;
181 :
182 : // ignore hidden documents
183 118 : if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
184 : return;
185 :
186 118 : ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
187 118 : ::rtl::OUString aFilter;
188 118 : const SfxFilter* pFilter = pMed->GetOrigFilter();
189 118 : if ( pFilter )
190 118 : aFilter = pFilter->GetFilterName();
191 :
192 : // add to svtool history options
193 : SvtHistoryOptions().AppendItem( ePICKLIST,
194 : aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
195 : aFilter,
196 : aTitle,
197 118 : SfxStringEncode( aURL.GetPass() ) );
198 :
199 118 : if ( aURL.GetProtocol() == INET_PROT_FILE )
200 118 : Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ), (pFilter) ? pFilter->GetMimeType() : ::rtl::OUString() );
201 : }
202 :
203 19 : SfxPickList& SfxPickList::Get()
204 : {
205 19 : static SfxPickList aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST));
206 19 : return aUniqueInstance;
207 : }
208 :
209 19 : SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
210 19 : m_nAllowedMenuSize( nAllowedMenuSize )
211 : {
212 19 : m_xStringLength = new StringLength;
213 19 : m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
214 19 : StartListening( *SFX_APP() );
215 19 : }
216 :
217 38 : SfxPickList::~SfxPickList()
218 : {
219 19 : RemovePickListEntries();
220 19 : }
221 :
222 0 : void SfxPickList::CreatePickListEntries()
223 : {
224 0 : RemovePickListEntries();
225 :
226 : // Reading the pick list
227 0 : Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
228 :
229 0 : sal_uInt32 nCount = seqPicklist.getLength();
230 0 : sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
231 :
232 0 : for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
233 : {
234 0 : Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
235 :
236 0 : INetURLObject aURL;
237 0 : ::rtl::OUString sURL;
238 0 : ::rtl::OUString sFilter;
239 0 : ::rtl::OUString sTitle;
240 0 : ::rtl::OUString sPassword;
241 :
242 0 : sal_uInt32 nPropertyCount = seqPropertySet.getLength();
243 0 : for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
244 : {
245 0 : if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
246 : {
247 0 : seqPropertySet[nProperty].Value >>= sURL;
248 : }
249 0 : else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
250 : {
251 0 : seqPropertySet[nProperty].Value >>= sFilter;
252 : }
253 0 : else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
254 : {
255 0 : seqPropertySet[nProperty].Value >>= sTitle;
256 : }
257 0 : else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_PASSWORD )
258 : {
259 0 : seqPropertySet[nProperty].Value >>= sPassword;
260 : }
261 : }
262 :
263 0 : aURL.SetSmartURL( sURL );
264 0 : aURL.SetPass( SfxStringDecode( sPassword ) );
265 :
266 0 : PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
267 0 : m_aPicklistVector.push_back( pPick );
268 0 : }
269 0 : }
270 :
271 0 : void SfxPickList::CreateMenuEntries( Menu* pMenu )
272 : {
273 0 : ::osl::MutexGuard aGuard( thePickListMutex::get() );
274 :
275 : static sal_Bool bPickListMenuInitializing = sal_False;
276 :
277 0 : if ( bPickListMenuInitializing ) // method is not reentrant!
278 0 : return;
279 :
280 0 : bPickListMenuInitializing = sal_True;
281 0 : CreatePickListEntries();
282 :
283 0 : for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
284 0 : pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
285 :
286 0 : if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
287 0 : pMenu->RemoveItem( pMenu->GetItemCount()-1 );
288 :
289 0 : if ( m_aPicklistVector.size() > 0 &&
290 0 : pMenu->GetItemType( pMenu->GetItemCount()-1 )
291 : != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
292 0 : pMenu->InsertSeparator();
293 :
294 0 : rtl::OUString aEmptyString;
295 0 : for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
296 : {
297 0 : PickListEntry* pEntry = GetPickListEntry( i );
298 :
299 0 : pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
300 0 : CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
301 : }
302 :
303 0 : bPickListMenuInitializing = sal_False;
304 : }
305 :
306 0 : void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
307 : {
308 0 : ::osl::ClearableMutexGuard aGuard( thePickListMutex::get() );
309 :
310 0 : PickListEntry *pPick = SfxPickList::Get().GetPickListEntry( nIndex );
311 :
312 0 : if ( pPick )
313 : {
314 0 : SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
315 0 : aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
316 0 : aReq.AppendItem( SfxStringItem( SID_REFERER, DEFINE_CONST_UNICODE( SFX_REFERER_USER ) ) );
317 0 : aReq.AppendItem( SfxStringItem( SID_TARGETNAME, DEFINE_CONST_UNICODE("_default") ) );
318 0 : String aFilter( pPick->aFilter );
319 0 : aGuard.clear();
320 :
321 0 : sal_uInt16 nPos=aFilter.Search('|');
322 0 : if( nPos != STRING_NOTFOUND )
323 : {
324 0 : rtl::OUString aOptions(aFilter.Copy(nPos).GetBuffer()+1);
325 0 : aFilter.Erase( nPos );
326 0 : aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
327 : }
328 :
329 0 : aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
330 0 : aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
331 0 : SFX_APP()->ExecuteSlot( aReq );
332 0 : }
333 0 : }
334 :
335 0 : void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
336 : {
337 0 : ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
338 0 : }
339 :
340 3424 : void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
341 : {
342 3424 : if ( rHint.IsA( TYPE( SfxStringHint )))
343 : {
344 235 : SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
345 :
346 235 : if ( pStringHint->GetId() == SID_OPENURL )
347 235 : INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
348 : }
349 :
350 3424 : if ( rHint.IsA( TYPE( SfxEventHint )))
351 : {
352 3037 : SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
353 : // only ObjectShell-related events with media interest
354 3037 : SfxObjectShell* pDocSh = pEventHint->GetObjShell();
355 3037 : if( !pDocSh )
356 0 : return;
357 :
358 3037 : switch ( pEventHint->GetEventId() )
359 : {
360 : case SFX_EVENT_CREATEDOC:
361 : {
362 1 : sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
363 1 : if ( bAllowModif )
364 1 : pDocSh->EnableSetModified( sal_False );
365 :
366 : using namespace ::com::sun::star;
367 : uno::Reference<document::XDocumentProperties> xDocProps(
368 1 : pDocSh->getDocProperties());
369 1 : if (xDocProps.is()) {
370 1 : xDocProps->setAuthor( SvtUserOptions().GetFullName() );
371 1 : ::DateTime now( ::DateTime::SYSTEM );
372 1 : xDocProps->setCreationDate( util::DateTime(
373 3 : now.Get100Sec(), now.GetSec(), now.GetMin(),
374 3 : now.GetHour(), now.GetDay(), now.GetMonth(),
375 7 : now.GetYear() ) );
376 : }
377 :
378 1 : if ( bAllowModif )
379 1 : pDocSh->EnableSetModified( bAllowModif );
380 : }
381 1 : break;
382 :
383 : case SFX_EVENT_OPENDOC:
384 : {
385 123 : SfxMedium *pMed = pDocSh->GetMedium();
386 123 : if( !pMed )
387 : return;
388 :
389 : // Unnamed Documents and embedded-Documents not in History
390 246 : if ( !pDocSh->HasName() ||
391 123 : SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
392 : return;
393 :
394 : // Help not in History
395 123 : INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
396 123 : if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
397 : return;
398 :
399 123 : ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
400 123 : ::rtl::OUString aFilter;
401 123 : const SfxFilter* pFilter = pMed->GetOrigFilter();
402 123 : if ( pFilter )
403 123 : aFilter = pFilter->GetFilterName();
404 :
405 : // add to svtool history options
406 : SvtHistoryOptions().AppendItem( eHISTORY,
407 : aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
408 : aFilter,
409 : aTitle,
410 123 : SfxStringEncode( aURL.GetPass() ) );
411 : }
412 123 : break;
413 :
414 : case SFX_EVENT_SAVEDOCDONE:
415 : case SFX_EVENT_SAVEASDOCDONE:
416 : case SFX_EVENT_SAVETODOCDONE:
417 : case SFX_EVENT_CLOSEDOC:
418 : {
419 118 : AddDocumentToPickList(pDocSh);
420 : }
421 118 : break;
422 :
423 : case SFX_EVENT_SAVEASDOC:
424 : {
425 0 : SfxMedium *pMedium = pDocSh->GetMedium();
426 0 : if (!pMedium)
427 : return;
428 :
429 : // We're starting a "Save As". Add the current document (if it's
430 : // not a "new" document) to the "Recent Documents" list before we
431 : // switch to the new path.
432 : // If the current document is new, path will be empty.
433 0 : rtl::OUString path = pMedium->GetOrigURL();
434 0 : if (!path.isEmpty())
435 : {
436 0 : AddDocumentToPickList(pDocSh);
437 0 : }
438 : }
439 0 : break;
440 : }
441 : }
442 : }
443 :
444 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|