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