bump product version to 4.2.0.1
[LibreOffice.git] / sfx2 / source / appl / sfxpicklist.cxx
blob4b5b3fd17a3c4d4fbdd03aa7f2e6671fccf23999
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 <sfx2/docfile.hxx>
46 #include "objshimp.hxx"
47 #include <sfx2/docfilt.hxx>
49 #include <rtl/instance.hxx>
51 #include <algorithm>
53 // ----------------------------------------------------------------------------
55 using namespace ::com::sun::star::uno;
56 using namespace ::com::sun::star::beans;
57 using namespace ::com::sun::star::util;
59 // ----------------------------------------------------------------------------
61 class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
63 public:
64 StringLength() {}
65 virtual ~StringLength() {}
67 // XStringWidth
68 sal_Int32 SAL_CALL queryStringWidth( const OUString& aString )
69 throw (::com::sun::star::uno::RuntimeException)
71 return aString.getLength();
75 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const OUString& aURLString, sal_uInt32 nNo )
77 OUStringBuffer aPickEntry;
79 if ( nNo < 9 )
81 aPickEntry.append('~');
82 aPickEntry.append(OUString::number(nNo + 1));
84 else if ( nNo == 9 )
85 aPickEntry.append("1~0");
86 else
87 aPickEntry.append(OUString::number(nNo + 1));
88 aPickEntry.append(": ");
90 INetURLObject aURL( aURLString );
91 OUString aTipHelpText;
92 OUString aAccessibleName = aPickEntry.toString();
94 if ( aURL.GetProtocol() == INET_PROT_FILE )
96 // Do handle file URL differently => convert it to a system
97 // path and abbreviate it with a special function:
98 OUString aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
100 OUString aSystemPath( aFileSystemPath );
101 OUString aCompactedSystemPath;
103 aTipHelpText = aSystemPath;
104 aAccessibleName += aSystemPath;
105 oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
106 if ( !nError )
107 aPickEntry.append( aCompactedSystemPath );
108 else
109 aPickEntry.append( aFileSystemPath );
111 if ( aPickEntry.getLength() > 50 )
113 aPickEntry.setLength( 47 );
114 aPickEntry.append("...");
117 else
119 // Use INetURLObject to abbreviate all other URLs
120 OUString aShortURL;
121 aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
122 aPickEntry.append(aShortURL);
123 aTipHelpText = aURLString;
124 aAccessibleName += aURLString;
127 // Set menu item text, tip help and accessible name
128 pMenu->SetItemText( nItemId, aPickEntry.toString() );
129 pMenu->SetTipHelpText( nItemId, aTipHelpText );
130 pMenu->SetAccessibleName( nItemId, aAccessibleName );
133 namespace
135 class thePickListMutex
136 : public rtl::Static<osl::Mutex, thePickListMutex> {};
139 void SfxPickList::RemovePickListEntries()
141 ::osl::MutexGuard aGuard( thePickListMutex::get() );
142 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
143 delete m_aPicklistVector[i];
144 m_aPicklistVector.clear();
147 SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
149 OSL_ASSERT( m_aPicklistVector.size() > nIndex );
151 if ( nIndex < m_aPicklistVector.size() )
152 return m_aPicklistVector[ nIndex ];
153 else
154 return 0;
157 void SfxPickList::AddDocumentToPickList( SfxObjectShell* pDocSh )
159 SfxMedium *pMed = pDocSh->GetMedium();
160 if( !pMed )
161 return;
163 // Unnamed Documents and embedded-Documents not in Picklist
164 if ( !pDocSh->HasName() ||
165 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
166 return;
168 // Help not in History
169 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : OUString( pMed->GetOrigURL() ) );
170 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
171 return;
173 if ( !pMed->IsUpdatePickList() )
174 return;
176 // add no document that forbids this (for example Message-Body)
177 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
178 if ( pPicklistItem && !pPicklistItem->GetValue() )
179 return;
181 // ignore hidden documents
182 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
183 return;
185 OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
186 OUString aFilter;
187 const SfxFilter* pFilter = pMed->GetOrigFilter();
188 if ( pFilter )
189 aFilter = pFilter->GetFilterName();
191 // add to svtool history options
192 SvtHistoryOptions().AppendItem( ePICKLIST,
193 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
194 aFilter,
195 aTitle,
196 OUString() );
198 if ( aURL.GetProtocol() == INET_PROT_FILE )
199 Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
200 (pFilter) ? pFilter->GetMimeType() : OUString(),
201 (pFilter) ? pFilter->GetServiceName() : OUString() );
204 SfxPickList& SfxPickList::Get()
206 static SfxPickList aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST));
207 return aUniqueInstance;
210 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
211 m_nAllowedMenuSize( nAllowedMenuSize )
213 m_xStringLength = new StringLength;
214 m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
215 StartListening( *SFX_APP() );
218 SfxPickList::~SfxPickList()
220 RemovePickListEntries();
223 void SfxPickList::CreatePickListEntries()
225 RemovePickListEntries();
227 // Reading the pick list
228 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
230 sal_uInt32 nCount = seqPicklist.getLength();
231 sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
233 for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
235 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
237 INetURLObject aURL;
238 OUString sURL;
239 OUString sFilter;
240 OUString sTitle;
242 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
243 for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
245 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
247 seqPropertySet[nProperty].Value >>= sURL;
249 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
251 seqPropertySet[nProperty].Value >>= sFilter;
253 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
255 seqPropertySet[nProperty].Value >>= sTitle;
259 aURL.SetSmartURL( sURL );
260 aURL.SetPass( OUString() );
262 PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
263 m_aPicklistVector.push_back( pPick );
267 void SfxPickList::CreateMenuEntries( Menu* pMenu )
269 ::osl::MutexGuard aGuard( thePickListMutex::get() );
271 static sal_Bool bPickListMenuInitializing = sal_False;
273 if ( bPickListMenuInitializing ) // method is not reentrant!
274 return;
276 bPickListMenuInitializing = sal_True;
277 CreatePickListEntries();
279 for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
280 pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
282 if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
283 pMenu->RemoveItem( pMenu->GetItemCount()-1 );
285 if ( m_aPicklistVector.size() > 0 &&
286 pMenu->GetItemType( pMenu->GetItemCount()-1 )
287 != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
288 pMenu->InsertSeparator();
290 OUString aEmptyString;
291 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
293 PickListEntry* pEntry = GetPickListEntry( i );
295 pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
296 CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
299 bPickListMenuInitializing = sal_False;
302 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
304 ::osl::ClearableMutexGuard aGuard( thePickListMutex::get() );
306 PickListEntry *pPick = SfxPickList::Get().GetPickListEntry( nIndex );
308 if ( pPick )
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, "private:user" ) );
313 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, "_default" ) );
314 OUString aFilter( pPick->aFilter );
315 aGuard.clear();
317 sal_Int32 nPos = aFilter.indexOf('|');
318 if( nPos != -1 )
320 OUString aOptions(aFilter.copy(nPos+1));
321 aFilter = aFilter.copy( 0, nPos );
322 aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
325 aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
326 aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
327 SFX_APP()->ExecuteSlot( aReq );
331 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
333 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
336 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
338 if ( rHint.IsA( TYPE( SfxStringHint )))
340 SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
342 if ( pStringHint->GetId() == SID_OPENURL )
343 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
346 if ( rHint.IsA( TYPE( SfxEventHint )))
348 SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
349 // only ObjectShell-related events with media interest
350 SfxObjectShell* pDocSh = pEventHint->GetObjShell();
351 if( !pDocSh )
352 return;
354 switch ( pEventHint->GetEventId() )
356 case SFX_EVENT_CREATEDOC:
358 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
359 if ( bAllowModif )
360 pDocSh->EnableSetModified( sal_False );
362 using namespace ::com::sun::star;
363 uno::Reference<document::XDocumentProperties> xDocProps(
364 pDocSh->getDocProperties());
365 if (xDocProps.is()) {
366 xDocProps->setAuthor( SvtUserOptions().GetFullName() );
367 ::DateTime now( ::DateTime::SYSTEM );
368 xDocProps->setCreationDate( util::DateTime(
369 now.GetNanoSec(), now.GetSec(), now.GetMin(),
370 now.GetHour(), now.GetDay(), now.GetMonth(),
371 now.GetYear(), false) );
374 if ( bAllowModif )
375 pDocSh->EnableSetModified( bAllowModif );
377 break;
379 case SFX_EVENT_OPENDOC:
381 AddDocumentToPickList(pDocSh);
383 break;
385 case SFX_EVENT_SAVEDOCDONE:
386 case SFX_EVENT_SAVEASDOCDONE:
387 case SFX_EVENT_SAVETODOCDONE:
388 case SFX_EVENT_CLOSEDOC:
390 AddDocumentToPickList(pDocSh);
392 break;
394 case SFX_EVENT_SAVEASDOC:
396 SfxMedium *pMedium = pDocSh->GetMedium();
397 if (!pMedium)
398 return;
400 // We're starting a "Save As". Add the current document (if it's
401 // not a "new" document) to the "Recent Documents" list before we
402 // switch to the new path.
403 // If the current document is new, path will be empty.
404 OUString path = pMedium->GetOrigURL();
405 if (!path.isEmpty())
407 AddDocumentToPickList(pDocSh);
410 break;
415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */