xref: /aoo41x/main/sfx2/source/appl/sfxpicklist.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sfx2.hxx"
30 
31 #include <com/sun/star/document/XDocumentProperties.hpp>
32 #include <unotools/historyoptions.hxx>
33 #include <unotools/useroptions.hxx>
34 #include <tools/urlobj.hxx>
35 #include <framework/menuconfiguration.hxx>
36 #include <svl/inethist.hxx>
37 #include <svl/stritem.hxx>
38 #include <svl/eitem.hxx>
39 #include <osl/file.hxx>
40 #include <unotools/localfilehelper.hxx>
41 #include <cppuhelper/implbase1.hxx>
42 
43 // ----------------------------------------------------------------------------
44 
45 #include <sfx2/app.hxx>
46 #include "sfxpicklist.hxx"
47 #include <sfx2/sfxuno.hxx>
48 #include "sfxtypes.hxx"
49 #include <sfx2/request.hxx>
50 #include <sfx2/sfxsids.hrc>
51 #include <sfx2/sfx.hrc>
52 #include <sfx2/event.hxx>
53 #include <sfx2/objsh.hxx>
54 #include <sfx2/bindings.hxx>
55 #include "referers.hxx"
56 #include <sfx2/docfile.hxx>
57 #include "objshimp.hxx"
58 #include <sfx2/docfilt.hxx>
59 
60 #include <algorithm>
61 
62 // ----------------------------------------------------------------------------
63 
64 using namespace ::com::sun::star::uno;
65 using namespace ::com::sun::star::beans;
66 using namespace ::com::sun::star::util;
67 
68 // ----------------------------------------------------------------------------
69 
70 osl::Mutex*		SfxPickList::pMutex = 0;
71 SfxPickList*	SfxPickList::pUniqueInstance = 0;
72 
73 // ----------------------------------------------------------------------------
74 
75 class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
76 {
77 	public:
78 		StringLength() {}
79 		virtual ~StringLength() {}
80 
81 		// XStringWidth
82 		sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
83 			throw (::com::sun::star::uno::RuntimeException)
84 		{
85 			return aString.getLength();
86 		}
87 };
88 
89 // ----------------------------------------------------------------------------
90 
91 osl::Mutex*	SfxPickList::GetOrCreateMutex()
92 {
93 	if ( !pMutex )
94 	{
95 		::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
96 		if ( !pMutex )
97 			pMutex = new osl::Mutex;
98 	}
99 
100 	return pMutex;
101 }
102 
103 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const String& aURLString, sal_uInt32 nNo )
104 {
105 	String aPickEntry;
106 
107 	if ( nNo < 9 )
108 	{
109 		aPickEntry += '~';
110 		aPickEntry += String::CreateFromInt32( nNo + 1 );
111 	}
112 	else if ( nNo == 9 )
113 		aPickEntry += DEFINE_CONST_UNICODE("1~0");
114 	else
115 		aPickEntry += String::CreateFromInt32( nNo + 1 );
116 	aPickEntry += DEFINE_CONST_UNICODE(": ");
117 
118 	INetURLObject	aURL( aURLString );
119 	rtl::OUString	aTipHelpText;
120 	rtl::OUString	aAccessibleName( aPickEntry );
121 
122 	if ( aURL.GetProtocol() == INET_PROT_FILE )
123 	{
124 		// Do handle file URL differently => convert it to a system
125 		// path and abbreviate it with a special function:
126 		String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
127 
128 //		::utl::LocalFileHelper::ConvertURLToPhysicalName( aURLString, aPhysicalName );
129 
130 		::rtl::OUString	aSystemPath( aFileSystemPath );
131 		::rtl::OUString	aCompactedSystemPath;
132 
133 		aTipHelpText = aSystemPath;
134 		aAccessibleName += aSystemPath;
135 		oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
136 		if ( !nError )
137 			aPickEntry += String( aCompactedSystemPath );
138 		else
139 			aPickEntry += aFileSystemPath;
140 
141 		if ( aPickEntry.Len() > 50 )
142 		{
143 			aPickEntry.Erase( 47 );
144 			aPickEntry += DEFINE_CONST_UNICODE("...");
145 		}
146 	}
147 	else
148 	{
149 		// Use INetURLObject to abbreviate all other URLs
150 		String	aShortURL;
151 		aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
152 		aPickEntry += aShortURL;
153 		aTipHelpText = aURLString;
154 		aAccessibleName += aURLString;
155 	}
156 
157 	// Set menu item text, tip help and accessible name
158 	pMenu->SetItemText( nItemId, aPickEntry );
159 	pMenu->SetTipHelpText( nItemId, aTipHelpText );
160 	pMenu->SetAccessibleName( nItemId, aAccessibleName );
161 }
162 
163 void SfxPickList::RemovePickListEntries()
164 {
165 	::osl::MutexGuard aGuard( GetOrCreateMutex() );
166 	for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
167 		delete m_aPicklistVector[i];
168 	m_aPicklistVector.clear();
169 }
170 
171 SfxPickList::PickListEntry*	SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
172 {
173 	OSL_ASSERT( m_aPicklistVector.size() > nIndex );
174 
175 	if ( nIndex < m_aPicklistVector.size() )
176 		return m_aPicklistVector[ nIndex ];
177 	else
178 		return 0;
179 }
180 
181 SfxPickList*	SfxPickList::GetOrCreate( const sal_uInt32 nMenuSize )
182 {
183 	if ( !pUniqueInstance )
184 	{
185 		::osl::MutexGuard aGuard( GetOrCreateMutex() );
186 		if ( !pUniqueInstance )
187 			pUniqueInstance = new SfxPickList( nMenuSize );
188 	}
189 
190 	return pUniqueInstance;
191 }
192 
193 SfxPickList* SfxPickList::Get()
194 {
195 	::osl::MutexGuard aGuard( GetOrCreateMutex() );
196 	return pUniqueInstance;
197 }
198 
199 void SfxPickList::Delete()
200 {
201 	::osl::MutexGuard aGuard( GetOrCreateMutex() );
202 	DELETEZ( pUniqueInstance );
203 }
204 
205 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
206 	m_nAllowedMenuSize( nAllowedMenuSize )
207 {
208 	m_xStringLength = new StringLength;
209 	m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
210 	StartListening( *SFX_APP() );
211 }
212 
213 SfxPickList::~SfxPickList()
214 {
215 	RemovePickListEntries();
216 }
217 
218 void SfxPickList::CreatePickListEntries()
219 {
220 	RemovePickListEntries();
221 
222 	// Einlesen der Pickliste
223 	Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
224 
225 	sal_uInt32 nCount	= seqPicklist.getLength();
226 	sal_uInt32 nEntries	= ::std::min( m_nAllowedMenuSize, nCount );
227 
228 	for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
229 	{
230 		Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
231 
232 		INetURLObject	aURL;
233 		::rtl::OUString sURL;
234 		::rtl::OUString sFilter;
235 		::rtl::OUString sTitle;
236 		::rtl::OUString sPassword;
237 
238 		sal_uInt32 nPropertyCount = seqPropertySet.getLength();
239 		for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
240 		{
241 			if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
242 			{
243 				seqPropertySet[nProperty].Value >>= sURL;
244 			}
245 			else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
246 			{
247 				seqPropertySet[nProperty].Value >>= sFilter;
248 			}
249 			else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
250 			{
251 				seqPropertySet[nProperty].Value >>= sTitle;
252 			}
253 			else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_PASSWORD )
254 			{
255 				seqPropertySet[nProperty].Value >>= sPassword;
256 			}
257 		}
258 
259 		aURL.SetSmartURL( sURL );
260 		aURL.SetPass( SfxStringDecode( sPassword ) );
261 
262 		PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
263 		m_aPicklistVector.push_back( pPick );
264 	}
265 }
266 
267 void SfxPickList::CreateMenuEntries( Menu* pMenu )
268 {
269 	static sal_Bool	bPickListMenuInitializing = sal_False;
270 
271 	::osl::MutexGuard aGuard( GetOrCreateMutex() );
272 
273 	if ( bPickListMenuInitializing ) // method is not reentrant!
274 		return;
275 
276 	bPickListMenuInitializing = sal_True;
277 	CreatePickListEntries();
278 
279     for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
280         pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
281 
282 	if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
283         pMenu->RemoveItem( pMenu->GetItemCount()-1 );
284 
285     if ( m_aPicklistVector.size() > 0 &&
286          pMenu->GetItemType( pMenu->GetItemCount()-1 )
287             != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
288         pMenu->InsertSeparator();
289 
290 	rtl::OUString aEmptyString;
291 	for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
292 	{
293 		PickListEntry* pEntry = GetPickListEntry( i );
294 
295 		pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
296 		CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
297 	}
298 
299 	bPickListMenuInitializing = sal_False;
300 }
301 
302 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
303 {
304 	::osl::ClearableMutexGuard aGuard( GetOrCreateMutex() );
305 
306 	PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
307 
308 	if ( pPick )
309 	{
310 		SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
311 		aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
312 		aReq.AppendItem( SfxStringItem( SID_REFERER, DEFINE_CONST_UNICODE( SFX_REFERER_USER ) ) );
313         aReq.AppendItem( SfxStringItem( SID_TARGETNAME, DEFINE_CONST_UNICODE("_default") ) );
314 		String aFilter( pPick->aFilter );
315 		aGuard.clear();
316 
317 		sal_uInt16 nPos=aFilter.Search('|');
318 		if( nPos != STRING_NOTFOUND )
319 		{
320 			String aOptions(aFilter.Copy( nPos ).GetBuffer()+1);
321 			aFilter.Erase( nPos );
322 			aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
323 		}
324 
325 		aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
326 		aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
327 		SFX_APP()->ExecuteSlot( aReq );
328 	}
329 }
330 
331 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
332 {
333 	ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
334 }
335 
336 String SfxPickList::GetMenuEntryTitle( sal_uInt32 nIndex )
337 {
338 	PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
339 
340 	if ( pPick )
341 		return pPick->aTitle;
342 	else
343 		return String();
344 }
345 
346 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
347 {
348 	if ( rHint.IsA( TYPE( SfxStringHint )))
349 	{
350 		SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
351 
352 		if ( pStringHint->GetId() == SID_OPENURL )
353 			INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
354 	}
355 
356 	if ( rHint.IsA( TYPE( SfxEventHint )))
357 	{
358 		SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
359 		// nur ObjectShell-bezogene Events mit Medium interessieren
360 		SfxObjectShell* pDocSh = pEventHint->GetObjShell();
361 		if( !pDocSh )
362 			return;
363 
364 		switch ( pEventHint->GetEventId() )
365 		{
366 			case SFX_EVENT_CREATEDOC:
367 			{
368                 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
369                 if ( bAllowModif )
370                     pDocSh->EnableSetModified( sal_False );
371 
372                 using namespace ::com::sun::star;
373                 uno::Reference<document::XDocumentProperties> xDocProps(
374                     pDocSh->getDocProperties());
375                 if (xDocProps.is()) {
376                     xDocProps->setAuthor( SvtUserOptions().GetFullName() );
377                     ::DateTime now;
378                     xDocProps->setCreationDate( util::DateTime(
379                         now.Get100Sec(), now.GetSec(), now.GetMin(),
380                         now.GetHour(), now.GetDay(), now.GetMonth(),
381                         now.GetYear() ) );
382                 }
383 
384                 if ( bAllowModif )
385                     pDocSh->EnableSetModified( bAllowModif );
386 			}
387             break;
388 
389             case SFX_EVENT_OPENDOC:
390             {
391                 SfxMedium *pMed = pDocSh->GetMedium();
392                 if( !pMed )
393                     return;
394 
395                 // unbenannt-Docs und embedded-Docs nicht in History
396                 if ( !pDocSh->HasName() ||
397                      SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
398                     return;
399 
400                 // Hilfe nicht in History
401 				INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
402                 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
403                     return;
404 
405                 ::rtl::OUString  aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
406                 ::rtl::OUString  aFilter;
407                 const SfxFilter* pFilter = pMed->GetOrigFilter();
408                 if ( pFilter )
409                     aFilter = pFilter->GetFilterName();
410 
411                 // add to svtool history options
412                 SvtHistoryOptions().AppendItem( eHISTORY,
413                         aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
414                         aFilter,
415                         aTitle,
416                         SfxStringEncode( aURL.GetPass() ) );
417             }
418             break;
419 
420 			case SFX_EVENT_CLOSEDOC:
421 			{
422 				SfxMedium *pMed = pDocSh->GetMedium();
423 				if( !pMed )
424 					return;
425 
426 				// unbenannt-Docs und embedded-Docs nicht in Pickliste
427 				if ( !pDocSh->HasName() ||
428 					 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
429 					return;
430 
431                 // Hilfe nicht in History
432 				INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
433                 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
434                     return;
435 
436                 // only add r/w document into picklist
437                 if ( pDocSh->IsReadOnly() || !pMed->IsUpdatePickList() )
438                     return;
439 
440                 // add no document that forbids this (for example Message-Body)
441                 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
442                 if (
443                     (pPicklistItem && !pPicklistItem->GetValue()) ||
444 				    (!(pDocSh->Get_Impl()->bWaitingForPicklist) )
445                    )
446                     return;
447 
448                 // ignore hidden documents
449                 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
450                     return;
451 
452                 ::rtl::OUString	 aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
453                 ::rtl::OUString	 aFilter;
454                 const SfxFilter* pFilter = pMed->GetOrigFilter();
455                 if ( pFilter )
456                     aFilter = pFilter->GetFilterName();
457 
458                 // add to svtool history options
459                 SvtHistoryOptions().AppendItem( ePICKLIST,
460                         aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
461                         aFilter,
462                         aTitle,
463                         SfxStringEncode( aURL.GetPass() ) );
464 
465                 pDocSh->Get_Impl()->bWaitingForPicklist = sal_False;
466 
467                 if ( aURL.GetProtocol() == INET_PROT_FILE )
468                     Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ), (pFilter) ? pFilter->GetMimeType() : String() );
469 			}
470             break;
471 		}
472 	}
473 }
474