1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <com/sun/star/document/XDocumentProperties.hpp>
31 #include <unotools/historyoptions.hxx>
32 #include <unotools/useroptions.hxx>
33 #include <tools/urlobj.hxx>
34 #include <framework/menuconfiguration.hxx>
35 #include <svl/inethist.hxx>
36 #include <svl/stritem.hxx>
37 #include <svl/eitem.hxx>
38 #include <osl/file.hxx>
39 #include <unotools/localfilehelper.hxx>
40 #include <cppuhelper/implbase1.hxx>
42 // ----------------------------------------------------------------------------
44 #include <sfx2/app.hxx>
45 #include "sfxpicklist.hxx"
46 #include <sfx2/sfxuno.hxx>
47 #include "sfxtypes.hxx"
48 #include <sfx2/request.hxx>
49 #include <sfx2/sfxsids.hrc>
50 #include <sfx2/sfx.hrc>
51 #include <sfx2/event.hxx>
52 #include <sfx2/objsh.hxx>
53 #include <sfx2/bindings.hxx>
54 #include "referers.hxx"
55 #include <sfx2/docfile.hxx>
56 #include "objshimp.hxx"
57 #include <sfx2/docfilt.hxx>
59 #include <rtl/instance.hxx>
63 // ----------------------------------------------------------------------------
65 using namespace ::com::sun::star::uno
;
66 using namespace ::com::sun::star::beans
;
67 using namespace ::com::sun::star::util
;
69 // ----------------------------------------------------------------------------
71 class StringLength
: public ::cppu::WeakImplHelper1
< XStringWidth
>
75 virtual ~StringLength() {}
78 sal_Int32 SAL_CALL
queryStringWidth( const ::rtl::OUString
& aString
)
79 throw (::com::sun::star::uno::RuntimeException
)
81 return aString
.getLength();
85 void SfxPickList::CreatePicklistMenuTitle( Menu
* pMenu
, sal_uInt16 nItemId
, const ::rtl::OUString
& aURLString
, sal_uInt32 nNo
)
87 ::rtl::OUStringBuffer aPickEntry
;
91 aPickEntry
.append('~');
92 aPickEntry
.append(::rtl::OUString::valueOf(static_cast<sal_Int32
>(nNo
+ 1)));
95 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM("1~0"));
97 aPickEntry
.append(::rtl::OUString::valueOf(static_cast<sal_Int32
>(nNo
+ 1)));
98 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
100 INetURLObject
aURL( aURLString
);
101 rtl::OUString aTipHelpText
;
102 rtl::OUString aAccessibleName
= aPickEntry
.toString();
104 if ( aURL
.GetProtocol() == INET_PROT_FILE
)
106 // Do handle file URL differently => convert it to a system
107 // path and abbreviate it with a special function:
108 ::rtl::OUString
aFileSystemPath( aURL
.getFSysPath( INetURLObject::FSYS_DETECT
) );
110 ::rtl::OUString
aSystemPath( aFileSystemPath
);
111 ::rtl::OUString aCompactedSystemPath
;
113 aTipHelpText
= aSystemPath
;
114 aAccessibleName
+= aSystemPath
;
115 oslFileError nError
= osl_abbreviateSystemPath( aSystemPath
.pData
, &aCompactedSystemPath
.pData
, 46, NULL
);
117 aPickEntry
.append( aCompactedSystemPath
);
119 aPickEntry
.append( aFileSystemPath
);
121 if ( aPickEntry
.getLength() > 50 )
123 aPickEntry
.setLength( 47 );
124 aPickEntry
.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
129 // Use INetURLObject to abbreviate all other URLs
130 ::rtl::OUString aShortURL
;
131 aShortURL
= aURL
.getAbbreviated( m_xStringLength
, 46, INetURLObject::DECODE_UNAMBIGUOUS
);
132 aPickEntry
.append(aShortURL
);
133 aTipHelpText
= aURLString
;
134 aAccessibleName
+= aURLString
;
137 // Set menu item text, tip help and accessible name
138 pMenu
->SetItemText( nItemId
, aPickEntry
.toString() );
139 pMenu
->SetTipHelpText( nItemId
, aTipHelpText
);
140 pMenu
->SetAccessibleName( nItemId
, aAccessibleName
);
145 class thePickListMutex
146 : public rtl::Static
<osl::Mutex
, thePickListMutex
> {};
149 void SfxPickList::RemovePickListEntries()
151 ::osl::MutexGuard
aGuard( thePickListMutex::get() );
152 for ( sal_uInt32 i
= 0; i
< m_aPicklistVector
.size(); i
++ )
153 delete m_aPicklistVector
[i
];
154 m_aPicklistVector
.clear();
157 SfxPickList::PickListEntry
* SfxPickList::GetPickListEntry( sal_uInt32 nIndex
)
159 OSL_ASSERT( m_aPicklistVector
.size() > nIndex
);
161 if ( nIndex
< m_aPicklistVector
.size() )
162 return m_aPicklistVector
[ nIndex
];
167 void SfxPickList::AddDocumentToPickList( SfxObjectShell
* pDocSh
)
169 SfxMedium
*pMed
= pDocSh
->GetMedium();
173 // Unnamed Documents and embedded-Documents not in Picklist
174 if ( !pDocSh
->HasName() ||
175 SFX_CREATE_MODE_STANDARD
!= pDocSh
->GetCreateMode() )
178 // Help not in History
179 INetURLObject
aURL( pDocSh
->IsDocShared() ? pDocSh
->GetSharedFileURL() : ::rtl::OUString( pMed
->GetOrigURL() ) );
180 if ( aURL
.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP
)
183 if ( !pMed
->IsUpdatePickList() )
186 // add no document that forbids this (for example Message-Body)
187 SFX_ITEMSET_ARG( pMed
->GetItemSet(), pPicklistItem
, SfxBoolItem
, SID_PICKLIST
, sal_False
);
188 if ( pPicklistItem
&& !pPicklistItem
->GetValue() )
191 // ignore hidden documents
192 if ( !SfxViewFrame::GetFirst( pDocSh
, sal_True
) )
195 ::rtl::OUString aTitle
= pDocSh
->GetTitle(SFX_TITLE_PICKLIST
);
196 ::rtl::OUString aFilter
;
197 const SfxFilter
* pFilter
= pMed
->GetOrigFilter();
199 aFilter
= pFilter
->GetFilterName();
201 // add to svtool history options
202 SvtHistoryOptions().AppendItem( ePICKLIST
,
203 aURL
.GetURLNoPass( INetURLObject::NO_DECODE
),
206 SfxStringEncode( aURL
.GetPass() ) );
208 if ( aURL
.GetProtocol() == INET_PROT_FILE
)
209 Application::AddToRecentDocumentList( aURL
.GetURLNoPass( INetURLObject::NO_DECODE
), (pFilter
) ? pFilter
->GetMimeType() : ::rtl::OUString() );
212 SfxPickList
& SfxPickList::Get()
214 static SfxPickList
aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST
));
215 return aUniqueInstance
;
218 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize
) :
219 m_nAllowedMenuSize( nAllowedMenuSize
)
221 m_xStringLength
= new StringLength
;
222 m_nAllowedMenuSize
= ::std::min( m_nAllowedMenuSize
, (sal_uInt32
)PICKLIST_MAXSIZE
);
223 StartListening( *SFX_APP() );
226 SfxPickList::~SfxPickList()
228 RemovePickListEntries();
231 void SfxPickList::CreatePickListEntries()
233 RemovePickListEntries();
235 // Reading the pick list
236 Sequence
< Sequence
< PropertyValue
> > seqPicklist
= SvtHistoryOptions().GetList( ePICKLIST
);
238 sal_uInt32 nCount
= seqPicklist
.getLength();
239 sal_uInt32 nEntries
= ::std::min( m_nAllowedMenuSize
, nCount
);
241 for( sal_uInt32 nItem
=0; nItem
< nEntries
; ++nItem
)
243 Sequence
< PropertyValue
> seqPropertySet
= seqPicklist
[ nItem
];
246 ::rtl::OUString sURL
;
247 ::rtl::OUString sFilter
;
248 ::rtl::OUString sTitle
;
249 ::rtl::OUString sPassword
;
251 sal_uInt32 nPropertyCount
= seqPropertySet
.getLength();
252 for( sal_uInt32 nProperty
=0; nProperty
<nPropertyCount
; ++nProperty
)
254 if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_URL
)
256 seqPropertySet
[nProperty
].Value
>>= sURL
;
258 else if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_FILTER
)
260 seqPropertySet
[nProperty
].Value
>>= sFilter
;
262 else if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_TITLE
)
264 seqPropertySet
[nProperty
].Value
>>= sTitle
;
266 else if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_PASSWORD
)
268 seqPropertySet
[nProperty
].Value
>>= sPassword
;
272 aURL
.SetSmartURL( sURL
);
273 aURL
.SetPass( SfxStringDecode( sPassword
) );
275 PickListEntry
*pPick
= new PickListEntry( aURL
.GetMainURL( INetURLObject::NO_DECODE
), sFilter
, sTitle
);
276 m_aPicklistVector
.push_back( pPick
);
280 void SfxPickList::CreateMenuEntries( Menu
* pMenu
)
282 ::osl::MutexGuard
aGuard( thePickListMutex::get() );
284 static sal_Bool bPickListMenuInitializing
= sal_False
;
286 if ( bPickListMenuInitializing
) // method is not reentrant!
289 bPickListMenuInitializing
= sal_True
;
290 CreatePickListEntries();
292 for ( sal_uInt16 nId
= START_ITEMID_PICKLIST
; nId
<= END_ITEMID_PICKLIST
; ++nId
)
293 pMenu
->RemoveItem( pMenu
->GetItemPos( nId
) );
295 if ( pMenu
->GetItemType( pMenu
->GetItemCount()-1 ) == MENUITEM_SEPARATOR
)
296 pMenu
->RemoveItem( pMenu
->GetItemCount()-1 );
298 if ( m_aPicklistVector
.size() > 0 &&
299 pMenu
->GetItemType( pMenu
->GetItemCount()-1 )
300 != MENUITEM_SEPARATOR
&& m_nAllowedMenuSize
)
301 pMenu
->InsertSeparator();
303 rtl::OUString aEmptyString
;
304 for ( sal_uInt32 i
= 0; i
< m_aPicklistVector
.size(); i
++ )
306 PickListEntry
* pEntry
= GetPickListEntry( i
);
308 pMenu
->InsertItem( (sal_uInt16
)(START_ITEMID_PICKLIST
+ i
), aEmptyString
);
309 CreatePicklistMenuTitle( pMenu
, (sal_uInt16
)(START_ITEMID_PICKLIST
+ i
), pEntry
->aName
, i
);
312 bPickListMenuInitializing
= sal_False
;
315 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex
)
317 ::osl::ClearableMutexGuard
aGuard( thePickListMutex::get() );
319 PickListEntry
*pPick
= SfxPickList::Get().GetPickListEntry( nIndex
);
323 SfxRequest
aReq( SID_OPENDOC
, SFX_CALLMODE_ASYNCHRON
, SFX_APP()->GetPool() );
324 aReq
.AppendItem( SfxStringItem( SID_FILE_NAME
, pPick
->aName
));
325 aReq
.AppendItem( SfxStringItem( SID_REFERER
, DEFINE_CONST_UNICODE( SFX_REFERER_USER
) ) );
326 aReq
.AppendItem( SfxStringItem( SID_TARGETNAME
, DEFINE_CONST_UNICODE("_default") ) );
327 String
aFilter( pPick
->aFilter
);
330 sal_uInt16 nPos
=aFilter
.Search('|');
331 if( nPos
!= STRING_NOTFOUND
)
333 String
aOptions(aFilter
.Copy( nPos
).GetBuffer()+1);
334 aFilter
.Erase( nPos
);
335 aReq
.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS
, aOptions
));
338 aReq
.AppendItem(SfxStringItem( SID_FILTER_NAME
, aFilter
));
339 aReq
.AppendItem( SfxBoolItem( SID_TEMPLATE
, sal_False
) );
340 SFX_APP()->ExecuteSlot( aReq
);
344 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId
)
346 ExecuteEntry( (sal_uInt32
)( nId
- START_ITEMID_PICKLIST
) );
349 void SfxPickList::Notify( SfxBroadcaster
&, const SfxHint
& rHint
)
351 if ( rHint
.IsA( TYPE( SfxStringHint
)))
353 SfxStringHint
* pStringHint
= (SfxStringHint
*) &rHint
;
355 if ( pStringHint
->GetId() == SID_OPENURL
)
356 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint
->GetObject() ));
359 if ( rHint
.IsA( TYPE( SfxEventHint
)))
361 SfxEventHint
* pEventHint
= PTR_CAST(SfxEventHint
,&rHint
);
362 // only ObjectShell-related events with media interest
363 SfxObjectShell
* pDocSh
= pEventHint
->GetObjShell();
367 switch ( pEventHint
->GetEventId() )
369 case SFX_EVENT_CREATEDOC
:
371 sal_Bool bAllowModif
= pDocSh
->IsEnableSetModified();
373 pDocSh
->EnableSetModified( sal_False
);
375 using namespace ::com::sun::star
;
376 uno::Reference
<document::XDocumentProperties
> xDocProps(
377 pDocSh
->getDocProperties());
378 if (xDocProps
.is()) {
379 xDocProps
->setAuthor( SvtUserOptions().GetFullName() );
380 ::DateTime
now( ::DateTime::SYSTEM
);
381 xDocProps
->setCreationDate( util::DateTime(
382 now
.Get100Sec(), now
.GetSec(), now
.GetMin(),
383 now
.GetHour(), now
.GetDay(), now
.GetMonth(),
388 pDocSh
->EnableSetModified( bAllowModif
);
392 case SFX_EVENT_OPENDOC
:
394 SfxMedium
*pMed
= pDocSh
->GetMedium();
398 // Unnamed Documents and embedded-Documents not in History
399 if ( !pDocSh
->HasName() ||
400 SFX_CREATE_MODE_STANDARD
!= pDocSh
->GetCreateMode() )
403 // Help not in History
404 INetURLObject
aURL( pDocSh
->IsDocShared() ? pDocSh
->GetSharedFileURL() : ::rtl::OUString( pMed
->GetOrigURL() ) );
405 if ( aURL
.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP
)
408 ::rtl::OUString aTitle
= pDocSh
->GetTitle(SFX_TITLE_PICKLIST
);
409 ::rtl::OUString aFilter
;
410 const SfxFilter
* pFilter
= pMed
->GetOrigFilter();
412 aFilter
= pFilter
->GetFilterName();
414 // add to svtool history options
415 SvtHistoryOptions().AppendItem( eHISTORY
,
416 aURL
.GetURLNoPass( INetURLObject::NO_DECODE
),
419 SfxStringEncode( aURL
.GetPass() ) );
423 case SFX_EVENT_SAVEDOCDONE
:
424 case SFX_EVENT_SAVEASDOCDONE
:
425 case SFX_EVENT_SAVETODOCDONE
:
426 case SFX_EVENT_CLOSEDOC
:
428 AddDocumentToPickList(pDocSh
);
432 case SFX_EVENT_SAVEASDOC
:
434 SfxMedium
*pMedium
= pDocSh
->GetMedium();
438 // We're starting a "Save As". Add the current document (if it's
439 // not a "new" document) to the "Recent Documents" list before we
440 // switch to the new path.
441 // If the current document is new, path will be empty.
442 rtl::OUString path
= pMedium
->GetOrigURL();
445 AddDocumentToPickList(pDocSh
);
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */