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