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/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>
33 // ----------------------------------------------------------------------------
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>
50 #include <rtl/instance.hxx>
54 // ----------------------------------------------------------------------------
56 using namespace ::com::sun::star::uno
;
57 using namespace ::com::sun::star::beans
;
58 using namespace ::com::sun::star::util
;
60 // ----------------------------------------------------------------------------
62 class StringLength
: public ::cppu::WeakImplHelper1
< XStringWidth
>
66 virtual ~StringLength() {}
69 sal_Int32 SAL_CALL
queryStringWidth( const OUString
& aString
)
70 throw (::com::sun::star::uno::RuntimeException
)
72 return aString
.getLength();
76 void SfxPickList::CreatePicklistMenuTitle( Menu
* pMenu
, sal_uInt16 nItemId
, const OUString
& aURLString
, sal_uInt32 nNo
)
78 OUStringBuffer aPickEntry
;
82 aPickEntry
.append('~');
83 aPickEntry
.append(OUString::valueOf(static_cast<sal_Int32
>(nNo
+ 1)));
86 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM("1~0"));
88 aPickEntry
.append(OUString::valueOf(static_cast<sal_Int32
>(nNo
+ 1)));
89 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
91 INetURLObject
aURL( aURLString
);
92 OUString aTipHelpText
;
93 OUString aAccessibleName
= aPickEntry
.toString();
95 if ( aURL
.GetProtocol() == INET_PROT_FILE
)
97 // Do handle file URL differently => convert it to a system
98 // path and abbreviate it with a special function:
99 OUString
aFileSystemPath( aURL
.getFSysPath( INetURLObject::FSYS_DETECT
) );
101 OUString
aSystemPath( aFileSystemPath
);
102 OUString aCompactedSystemPath
;
104 aTipHelpText
= aSystemPath
;
105 aAccessibleName
+= aSystemPath
;
106 oslFileError nError
= osl_abbreviateSystemPath( aSystemPath
.pData
, &aCompactedSystemPath
.pData
, 46, NULL
);
108 aPickEntry
.append( aCompactedSystemPath
);
110 aPickEntry
.append( aFileSystemPath
);
112 if ( aPickEntry
.getLength() > 50 )
114 aPickEntry
.setLength( 47 );
115 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
120 // Use INetURLObject to abbreviate all other URLs
122 aShortURL
= aURL
.getAbbreviated( m_xStringLength
, 46, INetURLObject::DECODE_UNAMBIGUOUS
);
123 aPickEntry
.append(aShortURL
);
124 aTipHelpText
= aURLString
;
125 aAccessibleName
+= aURLString
;
128 // Set menu item text, tip help and accessible name
129 pMenu
->SetItemText( nItemId
, aPickEntry
.toString() );
130 pMenu
->SetTipHelpText( nItemId
, aTipHelpText
);
131 pMenu
->SetAccessibleName( nItemId
, aAccessibleName
);
136 class thePickListMutex
137 : public rtl::Static
<osl::Mutex
, thePickListMutex
> {};
140 void SfxPickList::RemovePickListEntries()
142 ::osl::MutexGuard
aGuard( thePickListMutex::get() );
143 for ( sal_uInt32 i
= 0; i
< m_aPicklistVector
.size(); i
++ )
144 delete m_aPicklistVector
[i
];
145 m_aPicklistVector
.clear();
148 SfxPickList::PickListEntry
* SfxPickList::GetPickListEntry( sal_uInt32 nIndex
)
150 OSL_ASSERT( m_aPicklistVector
.size() > nIndex
);
152 if ( nIndex
< m_aPicklistVector
.size() )
153 return m_aPicklistVector
[ nIndex
];
158 void SfxPickList::AddDocumentToPickList( SfxObjectShell
* pDocSh
)
160 SfxMedium
*pMed
= pDocSh
->GetMedium();
164 // Unnamed Documents and embedded-Documents not in Picklist
165 if ( !pDocSh
->HasName() ||
166 SFX_CREATE_MODE_STANDARD
!= pDocSh
->GetCreateMode() )
169 // Help not in History
170 INetURLObject
aURL( pDocSh
->IsDocShared() ? pDocSh
->GetSharedFileURL() : OUString( pMed
->GetOrigURL() ) );
171 if ( aURL
.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP
)
174 if ( !pMed
->IsUpdatePickList() )
177 // add no document that forbids this (for example Message-Body)
178 SFX_ITEMSET_ARG( pMed
->GetItemSet(), pPicklistItem
, SfxBoolItem
, SID_PICKLIST
, sal_False
);
179 if ( pPicklistItem
&& !pPicklistItem
->GetValue() )
182 // ignore hidden documents
183 if ( !SfxViewFrame::GetFirst( pDocSh
, sal_True
) )
186 OUString aTitle
= pDocSh
->GetTitle(SFX_TITLE_PICKLIST
);
188 const SfxFilter
* pFilter
= pMed
->GetOrigFilter();
190 aFilter
= pFilter
->GetFilterName();
192 // add to svtool history options
193 SvtHistoryOptions().AppendItem( ePICKLIST
,
194 aURL
.GetURLNoPass( INetURLObject::NO_DECODE
),
199 if ( aURL
.GetProtocol() == INET_PROT_FILE
)
200 Application::AddToRecentDocumentList( aURL
.GetURLNoPass( INetURLObject::NO_DECODE
),
201 (pFilter
) ? pFilter
->GetMimeType() : OUString(),
202 (pFilter
) ? pFilter
->GetServiceName() : OUString() );
205 SfxPickList
& SfxPickList::Get()
207 static SfxPickList
aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST
));
208 return aUniqueInstance
;
211 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize
) :
212 m_nAllowedMenuSize( nAllowedMenuSize
)
214 m_xStringLength
= new StringLength
;
215 m_nAllowedMenuSize
= ::std::min( m_nAllowedMenuSize
, (sal_uInt32
)PICKLIST_MAXSIZE
);
216 StartListening( *SFX_APP() );
219 SfxPickList::~SfxPickList()
221 RemovePickListEntries();
224 void SfxPickList::CreatePickListEntries()
226 RemovePickListEntries();
228 // Reading the pick list
229 Sequence
< Sequence
< PropertyValue
> > seqPicklist
= SvtHistoryOptions().GetList( ePICKLIST
);
231 sal_uInt32 nCount
= seqPicklist
.getLength();
232 sal_uInt32 nEntries
= ::std::min( m_nAllowedMenuSize
, nCount
);
234 for( sal_uInt32 nItem
=0; nItem
< nEntries
; ++nItem
)
236 Sequence
< PropertyValue
> seqPropertySet
= seqPicklist
[ nItem
];
243 sal_uInt32 nPropertyCount
= seqPropertySet
.getLength();
244 for( sal_uInt32 nProperty
=0; nProperty
<nPropertyCount
; ++nProperty
)
246 if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_URL
)
248 seqPropertySet
[nProperty
].Value
>>= sURL
;
250 else if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_FILTER
)
252 seqPropertySet
[nProperty
].Value
>>= sFilter
;
254 else if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_TITLE
)
256 seqPropertySet
[nProperty
].Value
>>= sTitle
;
260 aURL
.SetSmartURL( sURL
);
261 aURL
.SetPass( OUString() );
263 PickListEntry
*pPick
= new PickListEntry( aURL
.GetMainURL( INetURLObject::NO_DECODE
), sFilter
, sTitle
);
264 m_aPicklistVector
.push_back( pPick
);
268 void SfxPickList::CreateMenuEntries( Menu
* pMenu
)
270 ::osl::MutexGuard
aGuard( thePickListMutex::get() );
272 static sal_Bool bPickListMenuInitializing
= sal_False
;
274 if ( bPickListMenuInitializing
) // method is not reentrant!
277 bPickListMenuInitializing
= sal_True
;
278 CreatePickListEntries();
280 for ( sal_uInt16 nId
= START_ITEMID_PICKLIST
; nId
<= END_ITEMID_PICKLIST
; ++nId
)
281 pMenu
->RemoveItem( pMenu
->GetItemPos( nId
) );
283 if ( pMenu
->GetItemType( pMenu
->GetItemCount()-1 ) == MENUITEM_SEPARATOR
)
284 pMenu
->RemoveItem( pMenu
->GetItemCount()-1 );
286 if ( m_aPicklistVector
.size() > 0 &&
287 pMenu
->GetItemType( pMenu
->GetItemCount()-1 )
288 != MENUITEM_SEPARATOR
&& m_nAllowedMenuSize
)
289 pMenu
->InsertSeparator();
291 OUString aEmptyString
;
292 for ( sal_uInt32 i
= 0; i
< m_aPicklistVector
.size(); i
++ )
294 PickListEntry
* pEntry
= GetPickListEntry( i
);
296 pMenu
->InsertItem( (sal_uInt16
)(START_ITEMID_PICKLIST
+ i
), aEmptyString
);
297 CreatePicklistMenuTitle( pMenu
, (sal_uInt16
)(START_ITEMID_PICKLIST
+ i
), pEntry
->aName
, i
);
300 bPickListMenuInitializing
= sal_False
;
303 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex
)
305 ::osl::ClearableMutexGuard
aGuard( thePickListMutex::get() );
307 PickListEntry
*pPick
= SfxPickList::Get().GetPickListEntry( nIndex
);
311 SfxRequest
aReq( SID_OPENDOC
, SFX_CALLMODE_ASYNCHRON
, SFX_APP()->GetPool() );
312 aReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, pPick
->aName
));
313 aReq
.AppendItem( SfxStringItem( SID_REFERER
, SFX_REFERER_USER
) );
314 aReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, "_default" ) );
315 String
aFilter( pPick
->aFilter
);
318 sal_uInt16 nPos
=aFilter
.Search('|');
319 if( nPos
!= STRING_NOTFOUND
)
321 OUString
aOptions(aFilter
.Copy(nPos
).GetBuffer()+1);
322 aFilter
.Erase( nPos
);
323 aReq
.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS
, aOptions
));
326 aReq
.AppendItem(SfxStringItem( SID_FILTER_NAME
, aFilter
));
327 aReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, sal_False
) );
328 SFX_APP()->ExecuteSlot( aReq
);
332 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId
)
334 ExecuteEntry( (sal_uInt32
)( nId
- START_ITEMID_PICKLIST
) );
337 void SfxPickList::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
339 if ( rHint
.IsA( TYPE( SfxStringHint
)))
341 SfxStringHint
* pStringHint
= (SfxStringHint
*) &rHint
;
343 if ( pStringHint
->GetId() == SID_OPENURL
)
344 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint
->GetObject() ));
347 if ( rHint
.IsA( TYPE( SfxEventHint
)))
349 SfxEventHint
* pEventHint
= PTR_CAST(SfxEventHint
,&rHint
);
350 // only ObjectShell-related events with media interest
351 SfxObjectShell
* pDocSh
= pEventHint
->GetObjShell();
355 switch ( pEventHint
->GetEventId() )
357 case SFX_EVENT_CREATEDOC
:
359 sal_Bool bAllowModif
= pDocSh
->IsEnableSetModified();
361 pDocSh
->EnableSetModified( sal_False
);
363 using namespace ::com::sun::star
;
364 uno::Reference
<document::XDocumentProperties
> xDocProps(
365 pDocSh
->getDocProperties());
366 if (xDocProps
.is()) {
367 xDocProps
->setAuthor( SvtUserOptions().GetFullName() );
368 ::DateTime
now( ::DateTime::SYSTEM
);
369 xDocProps
->setCreationDate( util::DateTime(
370 now
.GetNanoSec(), now
.GetSec(), now
.GetMin(),
371 now
.GetHour(), now
.GetDay(), now
.GetMonth(),
372 now
.GetYear(), false) );
376 pDocSh
->EnableSetModified( bAllowModif
);
380 case SFX_EVENT_OPENDOC
:
382 SfxMedium
*pMed
= pDocSh
->GetMedium();
386 // Unnamed Documents and embedded-Documents not in History
387 if ( !pDocSh
->HasName() ||
388 SFX_CREATE_MODE_STANDARD
!= pDocSh
->GetCreateMode() )
391 // Help not in History
392 INetURLObject
aURL( pDocSh
->IsDocShared() ? pDocSh
->GetSharedFileURL() : OUString( pMed
->GetOrigURL() ) );
393 if ( aURL
.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP
)
396 OUString aTitle
= pDocSh
->GetTitle(SFX_TITLE_PICKLIST
);
398 const SfxFilter
* pFilter
= pMed
->GetOrigFilter();
400 aFilter
= pFilter
->GetFilterName();
402 // add to svtool history options
403 SvtHistoryOptions().AppendItem( eHISTORY
,
404 aURL
.GetURLNoPass( INetURLObject::NO_DECODE
),
411 case SFX_EVENT_SAVEDOCDONE
:
412 case SFX_EVENT_SAVEASDOCDONE
:
413 case SFX_EVENT_SAVETODOCDONE
:
414 case SFX_EVENT_CLOSEDOC
:
416 AddDocumentToPickList(pDocSh
);
420 case SFX_EVENT_SAVEASDOC
:
422 SfxMedium
*pMedium
= pDocSh
->GetMedium();
426 // We're starting a "Save As". Add the current document (if it's
427 // not a "new" document) to the "Recent Documents" list before we
428 // switch to the new path.
429 // If the current document is new, path will be empty.
430 OUString path
= pMedium
->GetOrigURL();
433 AddDocumentToPickList(pDocSh
);
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */