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 {
80 return aString.getLength();
81 }
82 };
83
84 // ----------------------------------------------------------------------------
85
GetOrCreateMutex()86 osl::Mutex* SfxPickList::GetOrCreateMutex()
87 {
88 if ( !pMutex )
89 {
90 ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
91 if ( !pMutex )
92 pMutex = new osl::Mutex;
93 }
94
95 return pMutex;
96 }
97
CreatePicklistMenuTitle(Menu * pMenu,sal_uInt16 nItemId,const String & aURLString,sal_uInt32 nNo)98 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const String& aURLString, sal_uInt32 nNo )
99 {
100 String aPickEntry;
101
102 if ( nNo < 9 )
103 {
104 aPickEntry += '~';
105 aPickEntry += String::CreateFromInt32( nNo + 1 );
106 }
107 else if ( nNo == 9 )
108 aPickEntry += DEFINE_CONST_UNICODE("1~0");
109 else
110 aPickEntry += String::CreateFromInt32( nNo + 1 );
111 aPickEntry += DEFINE_CONST_UNICODE(": ");
112
113 INetURLObject aURL( aURLString );
114 rtl::OUString aTipHelpText;
115 rtl::OUString aAccessibleName( aPickEntry );
116
117 if ( aURL.GetProtocol() == INET_PROT_FILE )
118 {
119 // Do handle file URL differently => convert it to a system
120 // path and abbreviate it with a special function:
121 String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
122
123 // ::utl::LocalFileHelper::ConvertURLToPhysicalName( aURLString, aPhysicalName );
124
125 ::rtl::OUString aSystemPath( aFileSystemPath );
126 ::rtl::OUString aCompactedSystemPath;
127
128 aTipHelpText = aSystemPath;
129 aAccessibleName += aSystemPath;
130 oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
131 if ( !nError )
132 aPickEntry += String( aCompactedSystemPath );
133 else
134 aPickEntry += aFileSystemPath;
135
136 if ( aPickEntry.Len() > 50 )
137 {
138 aPickEntry.Erase( 47 );
139 aPickEntry += DEFINE_CONST_UNICODE("...");
140 }
141 }
142 else
143 {
144 // Use INetURLObject to abbreviate all other URLs
145 String aShortURL;
146 aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
147 aPickEntry += aShortURL;
148 aTipHelpText = aURLString;
149 aAccessibleName += aURLString;
150 }
151
152 // Set menu item text, tip help and accessible name
153 pMenu->SetItemText( nItemId, aPickEntry );
154 pMenu->SetTipHelpText( nItemId, aTipHelpText );
155 pMenu->SetAccessibleName( nItemId, aAccessibleName );
156 }
157
RemovePickListEntries()158 void SfxPickList::RemovePickListEntries()
159 {
160 ::osl::MutexGuard aGuard( GetOrCreateMutex() );
161 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
162 delete m_aPicklistVector[i];
163 m_aPicklistVector.clear();
164 }
165
GetPickListEntry(sal_uInt32 nIndex)166 SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
167 {
168 OSL_ASSERT( m_aPicklistVector.size() > nIndex );
169
170 if ( nIndex < m_aPicklistVector.size() )
171 return m_aPicklistVector[ nIndex ];
172 else
173 return 0;
174 }
175
GetOrCreate(const sal_uInt32 nMenuSize)176 SfxPickList* SfxPickList::GetOrCreate( const sal_uInt32 nMenuSize )
177 {
178 if ( !pUniqueInstance )
179 {
180 ::osl::MutexGuard aGuard( GetOrCreateMutex() );
181 if ( !pUniqueInstance )
182 pUniqueInstance = new SfxPickList( nMenuSize );
183 }
184
185 return pUniqueInstance;
186 }
187
Get()188 SfxPickList* SfxPickList::Get()
189 {
190 ::osl::MutexGuard aGuard( GetOrCreateMutex() );
191 return pUniqueInstance;
192 }
193
Delete()194 void SfxPickList::Delete()
195 {
196 ::osl::MutexGuard aGuard( GetOrCreateMutex() );
197 DELETEZ( pUniqueInstance );
198 }
199
SfxPickList(sal_uInt32 nAllowedMenuSize)200 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
201 m_nAllowedMenuSize( nAllowedMenuSize )
202 {
203 m_xStringLength = new StringLength;
204 m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
205 StartListening( *SFX_APP() );
206 }
207
~SfxPickList()208 SfxPickList::~SfxPickList()
209 {
210 RemovePickListEntries();
211 }
212
CreatePickListEntries()213 void SfxPickList::CreatePickListEntries()
214 {
215 RemovePickListEntries();
216
217 // Einlesen der Pickliste
218 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
219
220 sal_uInt32 nCount = seqPicklist.getLength();
221 sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
222
223 for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
224 {
225 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
226
227 INetURLObject aURL;
228 ::rtl::OUString sURL;
229 ::rtl::OUString sFilter;
230 ::rtl::OUString sTitle;
231 ::rtl::OUString sPassword;
232
233 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
234 for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
235 {
236 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
237 {
238 seqPropertySet[nProperty].Value >>= sURL;
239 }
240 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
241 {
242 seqPropertySet[nProperty].Value >>= sFilter;
243 }
244 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
245 {
246 seqPropertySet[nProperty].Value >>= sTitle;
247 }
248 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_PASSWORD )
249 {
250 seqPropertySet[nProperty].Value >>= sPassword;
251 }
252 }
253
254 aURL.SetSmartURL( sURL );
255 aURL.SetPass( SfxStringDecode( sPassword ) );
256
257 PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
258 m_aPicklistVector.push_back( pPick );
259 }
260 }
261
CreateMenuEntries(Menu * pMenu)262 void SfxPickList::CreateMenuEntries( Menu* pMenu )
263 {
264 static sal_Bool bPickListMenuInitializing = sal_False;
265
266 ::osl::MutexGuard aGuard( GetOrCreateMutex() );
267
268 if ( bPickListMenuInitializing ) // method is not reentrant!
269 return;
270
271 bPickListMenuInitializing = sal_True;
272 CreatePickListEntries();
273
274 for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
275 pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
276
277 if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
278 pMenu->RemoveItem( pMenu->GetItemCount()-1 );
279
280 if ( m_aPicklistVector.size() > 0 &&
281 pMenu->GetItemType( pMenu->GetItemCount()-1 )
282 != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
283 pMenu->InsertSeparator();
284
285 rtl::OUString aEmptyString;
286 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
287 {
288 PickListEntry* pEntry = GetPickListEntry( i );
289
290 pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
291 CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
292 }
293
294 bPickListMenuInitializing = sal_False;
295 }
296
ExecuteEntry(sal_uInt32 nIndex)297 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
298 {
299 ::osl::ClearableMutexGuard aGuard( GetOrCreateMutex() );
300
301 PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
302
303 if ( pPick )
304 {
305 SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
306 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
307 aReq.AppendItem( SfxStringItem( SID_REFERER, DEFINE_CONST_UNICODE( SFX_REFERER_USER ) ) );
308 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, DEFINE_CONST_UNICODE("_default") ) );
309 String aFilter( pPick->aFilter );
310 aGuard.clear();
311
312 sal_uInt16 nPos=aFilter.Search('|');
313 if( nPos != STRING_NOTFOUND )
314 {
315 String aOptions(aFilter.Copy( nPos ).GetBuffer()+1);
316 aFilter.Erase( nPos );
317 aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
318 }
319
320 aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
321 aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
322 SFX_APP()->ExecuteSlot( aReq );
323 }
324 }
325
ExecuteMenuEntry(sal_uInt16 nId)326 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
327 {
328 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
329 }
330
GetMenuEntryTitle(sal_uInt32 nIndex)331 String SfxPickList::GetMenuEntryTitle( sal_uInt32 nIndex )
332 {
333 PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
334
335 if ( pPick )
336 return pPick->aTitle;
337 else
338 return String();
339 }
340
Notify(SfxBroadcaster &,const SfxHint & rHint)341 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
342 {
343 if ( rHint.IsA( TYPE( SfxStringHint )))
344 {
345 SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
346
347 if ( pStringHint->GetId() == SID_OPENURL )
348 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
349 }
350
351 if ( rHint.IsA( TYPE( SfxEventHint )))
352 {
353 SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
354 // nur ObjectShell-bezogene Events mit Medium interessieren
355 SfxObjectShell* pDocSh = pEventHint->GetObjShell();
356 if( !pDocSh )
357 return;
358
359 switch ( pEventHint->GetEventId() )
360 {
361 case SFX_EVENT_CREATEDOC:
362 {
363 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
364 if ( bAllowModif )
365 pDocSh->EnableSetModified( sal_False );
366
367 using namespace ::com::sun::star;
368 uno::Reference<document::XDocumentProperties> xDocProps(
369 pDocSh->getDocProperties());
370 if (xDocProps.is()) {
371 xDocProps->setAuthor( SvtUserOptions().GetFullName() );
372 ::DateTime now;
373 xDocProps->setCreationDate( util::DateTime(
374 now.Get100Sec(), now.GetSec(), now.GetMin(),
375 now.GetHour(), now.GetDay(), now.GetMonth(),
376 now.GetYear() ) );
377 }
378
379 if ( bAllowModif )
380 pDocSh->EnableSetModified( bAllowModif );
381 }
382 break;
383
384 case SFX_EVENT_OPENDOC:
385 {
386 SfxMedium *pMed = pDocSh->GetMedium();
387 if( !pMed )
388 return;
389
390 // unbenannt-Docs und embedded-Docs nicht in History
391 if ( !pDocSh->HasName() ||
392 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
393 return;
394
395 // Hilfe nicht in History
396 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
397 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
398 return;
399
400 ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
401 ::rtl::OUString aFilter;
402 const SfxFilter* pFilter = pMed->GetOrigFilter();
403 if ( pFilter )
404 aFilter = pFilter->GetFilterName();
405
406 // add to svtool history options
407 SvtHistoryOptions().AppendItem( eHISTORY,
408 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
409 aFilter,
410 aTitle,
411 SfxStringEncode( aURL.GetPass() ) );
412 }
413 break;
414
415 case SFX_EVENT_CLOSEDOC:
416 {
417 SfxMedium *pMed = pDocSh->GetMedium();
418 if( !pMed )
419 return;
420
421 // unbenannt-Docs und embedded-Docs nicht in Pickliste
422 if ( !pDocSh->HasName() ||
423 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
424 return;
425
426 // Hilfe nicht in History
427 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
428 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
429 return;
430
431 // only add r/w document into picklist
432 if ( pDocSh->IsReadOnly() || !pMed->IsUpdatePickList() )
433 return;
434
435 // add no document that forbids this (for example Message-Body)
436 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
437 if (
438 (pPicklistItem && !pPicklistItem->GetValue()) ||
439 (!(pDocSh->Get_Impl()->bWaitingForPicklist) )
440 )
441 return;
442
443 // ignore hidden documents
444 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
445 return;
446
447 ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
448 ::rtl::OUString aFilter;
449 const SfxFilter* pFilter = pMed->GetOrigFilter();
450 if ( pFilter )
451 aFilter = pFilter->GetFilterName();
452
453 // add to svtool history options
454 SvtHistoryOptions().AppendItem( ePICKLIST,
455 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
456 aFilter,
457 aTitle,
458 SfxStringEncode( aURL.GetPass() ) );
459
460 pDocSh->Get_Impl()->bWaitingForPicklist = sal_False;
461
462 if ( aURL.GetProtocol() == INET_PROT_FILE )
463 Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ), (pFilter) ? pFilter->GetMimeType() : String() );
464 }
465 break;
466 }
467 }
468 }
469