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: 74 StringLength() {} 75 virtual ~StringLength() {} 76 77 // XStringWidth 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 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 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 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 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 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 189 SfxPickList* SfxPickList::Get() 190 { 191 ::osl::MutexGuard aGuard( GetOrCreateMutex() ); 192 return pUniqueInstance; 193 } 194 195 void SfxPickList::Delete() 196 { 197 ::osl::MutexGuard aGuard( GetOrCreateMutex() ); 198 DELETEZ( pUniqueInstance ); 199 } 200 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 209 SfxPickList::~SfxPickList() 210 { 211 RemovePickListEntries(); 212 } 213 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 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 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 327 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId ) 328 { 329 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) ); 330 } 331 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 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