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 { 80 return aString.getLength(); 81 } 82 }; 83 84 // ---------------------------------------------------------------------------- 85 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 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 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 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 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 188 SfxPickList* SfxPickList::Get() 189 { 190 ::osl::MutexGuard aGuard( GetOrCreateMutex() ); 191 return pUniqueInstance; 192 } 193 194 void SfxPickList::Delete() 195 { 196 ::osl::MutexGuard aGuard( GetOrCreateMutex() ); 197 DELETEZ( pUniqueInstance ); 198 } 199 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 208 SfxPickList::~SfxPickList() 209 { 210 RemovePickListEntries(); 211 } 212 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 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 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 326 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId ) 327 { 328 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) ); 329 } 330 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 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