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