bump product version to 4.1.6.2
[LibreOffice.git] / sfx2 / source / appl / sfxpicklist.cxx
blob32b3ea561badb3210b3f55b25e7f587483b720d0
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <com/sun/star/document/XDocumentProperties.hpp>
22 #include <unotools/historyoptions.hxx>
23 #include <unotools/useroptions.hxx>
24 #include <tools/urlobj.hxx>
25 #include <framework/menuconfiguration.hxx>
26 #include <svl/inethist.hxx>
27 #include <svl/stritem.hxx>
28 #include <svl/eitem.hxx>
29 #include <osl/file.hxx>
30 #include <unotools/localfilehelper.hxx>
31 #include <cppuhelper/implbase1.hxx>
33 // ----------------------------------------------------------------------------
35 #include <sfx2/app.hxx>
36 #include "sfxpicklist.hxx"
37 #include <sfx2/sfxuno.hxx>
38 #include "sfxtypes.hxx"
39 #include <sfx2/request.hxx>
40 #include <sfx2/sfxsids.hrc>
41 #include <sfx2/sfx.hrc>
42 #include <sfx2/event.hxx>
43 #include <sfx2/objsh.hxx>
44 #include <sfx2/bindings.hxx>
45 #include "referers.hxx"
46 #include <sfx2/docfile.hxx>
47 #include "objshimp.hxx"
48 #include <sfx2/docfilt.hxx>
50 #include <rtl/instance.hxx>
52 #include <algorithm>
54 // ----------------------------------------------------------------------------
56 using namespace ::com::sun::star::uno;
57 using namespace ::com::sun::star::beans;
58 using namespace ::com::sun::star::util;
60 // ----------------------------------------------------------------------------
62 class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
64 public:
65 StringLength() {}
66 virtual ~StringLength() {}
68 // XStringWidth
69 sal_Int32 SAL_CALL queryStringWidth( const OUString& aString )
70 throw (::com::sun::star::uno::RuntimeException)
72 return aString.getLength();
76 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const OUString& aURLString, sal_uInt32 nNo )
78 OUStringBuffer aPickEntry;
80 if ( nNo < 9 )
82 aPickEntry.append('~');
83 aPickEntry.append(OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
85 else if ( nNo == 9 )
86 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("1~0"));
87 else
88 aPickEntry.append(OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
89 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
91 INetURLObject aURL( aURLString );
92 OUString aTipHelpText;
93 OUString aAccessibleName = aPickEntry.toString();
95 if ( aURL.GetProtocol() == INET_PROT_FILE )
97 // Do handle file URL differently => convert it to a system
98 // path and abbreviate it with a special function:
99 OUString aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
101 OUString aSystemPath( aFileSystemPath );
102 OUString aCompactedSystemPath;
104 aTipHelpText = aSystemPath;
105 aAccessibleName += aSystemPath;
106 oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
107 if ( !nError )
108 aPickEntry.append( aCompactedSystemPath );
109 else
110 aPickEntry.append( aFileSystemPath );
112 if ( aPickEntry.getLength() > 50 )
114 aPickEntry.setLength( 47 );
115 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
118 else
120 // Use INetURLObject to abbreviate all other URLs
121 OUString aShortURL;
122 aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
123 aPickEntry.append(aShortURL);
124 aTipHelpText = aURLString;
125 aAccessibleName += aURLString;
128 // Set menu item text, tip help and accessible name
129 pMenu->SetItemText( nItemId, aPickEntry.toString() );
130 pMenu->SetTipHelpText( nItemId, aTipHelpText );
131 pMenu->SetAccessibleName( nItemId, aAccessibleName );
134 namespace
136 class thePickListMutex
137 : public rtl::Static<osl::Mutex, thePickListMutex> {};
140 void SfxPickList::RemovePickListEntries()
142 ::osl::MutexGuard aGuard( thePickListMutex::get() );
143 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
144 delete m_aPicklistVector[i];
145 m_aPicklistVector.clear();
148 SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
150 OSL_ASSERT( m_aPicklistVector.size() > nIndex );
152 if ( nIndex < m_aPicklistVector.size() )
153 return m_aPicklistVector[ nIndex ];
154 else
155 return 0;
158 void SfxPickList::AddDocumentToPickList( SfxObjectShell* pDocSh )
160 SfxMedium *pMed = pDocSh->GetMedium();
161 if( !pMed )
162 return;
164 // Unnamed Documents and embedded-Documents not in Picklist
165 if ( !pDocSh->HasName() ||
166 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
167 return;
169 // Help not in History
170 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : OUString( pMed->GetOrigURL() ) );
171 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
172 return;
174 if ( !pMed->IsUpdatePickList() )
175 return;
177 // add no document that forbids this (for example Message-Body)
178 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
179 if ( pPicklistItem && !pPicklistItem->GetValue() )
180 return;
182 // ignore hidden documents
183 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
184 return;
186 OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
187 OUString aFilter;
188 const SfxFilter* pFilter = pMed->GetOrigFilter();
189 if ( pFilter )
190 aFilter = pFilter->GetFilterName();
192 // add to svtool history options
193 SvtHistoryOptions().AppendItem( ePICKLIST,
194 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
195 aFilter,
196 aTitle,
197 OUString() );
199 if ( aURL.GetProtocol() == INET_PROT_FILE )
200 Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
201 (pFilter) ? pFilter->GetMimeType() : OUString(),
202 (pFilter) ? pFilter->GetServiceName() : OUString() );
205 SfxPickList& SfxPickList::Get()
207 static SfxPickList aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST));
208 return aUniqueInstance;
211 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
212 m_nAllowedMenuSize( nAllowedMenuSize )
214 m_xStringLength = new StringLength;
215 m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
216 StartListening( *SFX_APP() );
219 SfxPickList::~SfxPickList()
221 RemovePickListEntries();
224 void SfxPickList::CreatePickListEntries()
226 RemovePickListEntries();
228 // Reading the pick list
229 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
231 sal_uInt32 nCount = seqPicklist.getLength();
232 sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
234 for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
236 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
238 INetURLObject aURL;
239 OUString sURL;
240 OUString sFilter;
241 OUString sTitle;
243 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
244 for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
246 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
248 seqPropertySet[nProperty].Value >>= sURL;
250 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
252 seqPropertySet[nProperty].Value >>= sFilter;
254 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
256 seqPropertySet[nProperty].Value >>= sTitle;
260 aURL.SetSmartURL( sURL );
261 aURL.SetPass( OUString() );
263 PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
264 m_aPicklistVector.push_back( pPick );
268 void SfxPickList::CreateMenuEntries( Menu* pMenu )
270 ::osl::MutexGuard aGuard( thePickListMutex::get() );
272 static sal_Bool bPickListMenuInitializing = sal_False;
274 if ( bPickListMenuInitializing ) // method is not reentrant!
275 return;
277 bPickListMenuInitializing = sal_True;
278 CreatePickListEntries();
280 for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
281 pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
283 if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
284 pMenu->RemoveItem( pMenu->GetItemCount()-1 );
286 if ( m_aPicklistVector.size() > 0 &&
287 pMenu->GetItemType( pMenu->GetItemCount()-1 )
288 != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
289 pMenu->InsertSeparator();
291 OUString aEmptyString;
292 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
294 PickListEntry* pEntry = GetPickListEntry( i );
296 pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
297 CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
300 bPickListMenuInitializing = sal_False;
303 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
305 ::osl::ClearableMutexGuard aGuard( thePickListMutex::get() );
307 PickListEntry *pPick = SfxPickList::Get().GetPickListEntry( nIndex );
309 if ( pPick )
311 SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
312 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
313 aReq.AppendItem( SfxStringItem( SID_REFERER, SFX_REFERER_USER ) );
314 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
315 String aFilter( pPick->aFilter );
316 aGuard.clear();
318 sal_uInt16 nPos=aFilter.Search('|');
319 if( nPos != STRING_NOTFOUND )
321 OUString aOptions(aFilter.Copy(nPos).GetBuffer()+1);
322 aFilter.Erase( nPos );
323 aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
326 aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
327 aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
328 SFX_APP()->ExecuteSlot( aReq );
332 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
334 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
337 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
339 if ( rHint.IsA( TYPE( SfxStringHint )))
341 SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
343 if ( pStringHint->GetId() == SID_OPENURL )
344 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
347 if ( rHint.IsA( TYPE( SfxEventHint )))
349 SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
350 // only ObjectShell-related events with media interest
351 SfxObjectShell* pDocSh = pEventHint->GetObjShell();
352 if( !pDocSh )
353 return;
355 switch ( pEventHint->GetEventId() )
357 case SFX_EVENT_CREATEDOC:
359 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
360 if ( bAllowModif )
361 pDocSh->EnableSetModified( sal_False );
363 using namespace ::com::sun::star;
364 uno::Reference<document::XDocumentProperties> xDocProps(
365 pDocSh->getDocProperties());
366 if (xDocProps.is()) {
367 xDocProps->setAuthor( SvtUserOptions().GetFullName() );
368 ::DateTime now( ::DateTime::SYSTEM );
369 xDocProps->setCreationDate( util::DateTime(
370 now.GetNanoSec(), now.GetSec(), now.GetMin(),
371 now.GetHour(), now.GetDay(), now.GetMonth(),
372 now.GetYear(), false) );
375 if ( bAllowModif )
376 pDocSh->EnableSetModified( bAllowModif );
378 break;
380 case SFX_EVENT_OPENDOC:
382 SfxMedium *pMed = pDocSh->GetMedium();
383 if( !pMed )
384 return;
386 // Unnamed Documents and embedded-Documents not in History
387 if ( !pDocSh->HasName() ||
388 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
389 return;
391 // Help not in History
392 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : OUString( pMed->GetOrigURL() ) );
393 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
394 return;
396 OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
397 OUString aFilter;
398 const SfxFilter* pFilter = pMed->GetOrigFilter();
399 if ( pFilter )
400 aFilter = pFilter->GetFilterName();
402 // add to svtool history options
403 SvtHistoryOptions().AppendItem( eHISTORY,
404 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
405 aFilter,
406 aTitle,
407 OUString() );
409 break;
411 case SFX_EVENT_SAVEDOCDONE:
412 case SFX_EVENT_SAVEASDOCDONE:
413 case SFX_EVENT_SAVETODOCDONE:
414 case SFX_EVENT_CLOSEDOC:
416 AddDocumentToPickList(pDocSh);
418 break;
420 case SFX_EVENT_SAVEASDOC:
422 SfxMedium *pMedium = pDocSh->GetMedium();
423 if (!pMedium)
424 return;
426 // We're starting a "Save As". Add the current document (if it's
427 // not a "new" document) to the "Recent Documents" list before we
428 // switch to the new path.
429 // If the current document is new, path will be empty.
430 OUString path = pMedium->GetOrigURL();
431 if (!path.isEmpty())
433 AddDocumentToPickList(pDocSh);
436 break;
441 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */