Version 3.6.0.4, tag libreoffice-3.6.0.4
[LibreOffice.git] / sfx2 / source / appl / sfxpicklist.cxx
blobb3c48f2c622fbfdf46de3dc53dc5c21a60fed99f
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 #include <com/sun/star/document/XDocumentProperties.hpp>
31 #include <unotools/historyoptions.hxx>
32 #include <unotools/useroptions.hxx>
33 #include <tools/urlobj.hxx>
34 #include <framework/menuconfiguration.hxx>
35 #include <svl/inethist.hxx>
36 #include <svl/stritem.hxx>
37 #include <svl/eitem.hxx>
38 #include <osl/file.hxx>
39 #include <unotools/localfilehelper.hxx>
40 #include <cppuhelper/implbase1.hxx>
42 // ----------------------------------------------------------------------------
44 #include <sfx2/app.hxx>
45 #include "sfxpicklist.hxx"
46 #include <sfx2/sfxuno.hxx>
47 #include "sfxtypes.hxx"
48 #include <sfx2/request.hxx>
49 #include <sfx2/sfxsids.hrc>
50 #include <sfx2/sfx.hrc>
51 #include <sfx2/event.hxx>
52 #include <sfx2/objsh.hxx>
53 #include <sfx2/bindings.hxx>
54 #include "referers.hxx"
55 #include <sfx2/docfile.hxx>
56 #include "objshimp.hxx"
57 #include <sfx2/docfilt.hxx>
59 #include <rtl/instance.hxx>
61 #include <algorithm>
63 // ----------------------------------------------------------------------------
65 using namespace ::com::sun::star::uno;
66 using namespace ::com::sun::star::beans;
67 using namespace ::com::sun::star::util;
69 // ----------------------------------------------------------------------------
71 class StringLength : public ::cppu::WeakImplHelper1< XStringWidth >
73 public:
74 StringLength() {}
75 virtual ~StringLength() {}
77 // XStringWidth
78 sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
79 throw (::com::sun::star::uno::RuntimeException)
81 return aString.getLength();
85 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const ::rtl::OUString& aURLString, sal_uInt32 nNo )
87 ::rtl::OUStringBuffer aPickEntry;
89 if ( nNo < 9 )
91 aPickEntry.append('~');
92 aPickEntry.append(::rtl::OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
94 else if ( nNo == 9 )
95 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("1~0"));
96 else
97 aPickEntry.append(::rtl::OUString::valueOf(static_cast<sal_Int32>(nNo + 1)));
98 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM(": "));
100 INetURLObject aURL( aURLString );
101 rtl::OUString aTipHelpText;
102 rtl::OUString aAccessibleName = aPickEntry.toString();
104 if ( aURL.GetProtocol() == INET_PROT_FILE )
106 // Do handle file URL differently => convert it to a system
107 // path and abbreviate it with a special function:
108 ::rtl::OUString aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
110 ::rtl::OUString aSystemPath( aFileSystemPath );
111 ::rtl::OUString aCompactedSystemPath;
113 aTipHelpText = aSystemPath;
114 aAccessibleName += aSystemPath;
115 oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
116 if ( !nError )
117 aPickEntry.append( aCompactedSystemPath );
118 else
119 aPickEntry.append( aFileSystemPath );
121 if ( aPickEntry.getLength() > 50 )
123 aPickEntry.setLength( 47 );
124 aPickEntry.appendAscii(RTL_CONSTASCII_STRINGPARAM("..."));
127 else
129 // Use INetURLObject to abbreviate all other URLs
130 ::rtl::OUString aShortURL;
131 aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
132 aPickEntry.append(aShortURL);
133 aTipHelpText = aURLString;
134 aAccessibleName += aURLString;
137 // Set menu item text, tip help and accessible name
138 pMenu->SetItemText( nItemId, aPickEntry.toString() );
139 pMenu->SetTipHelpText( nItemId, aTipHelpText );
140 pMenu->SetAccessibleName( nItemId, aAccessibleName );
143 namespace
145 class thePickListMutex
146 : public rtl::Static<osl::Mutex, thePickListMutex> {};
149 void SfxPickList::RemovePickListEntries()
151 ::osl::MutexGuard aGuard( thePickListMutex::get() );
152 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
153 delete m_aPicklistVector[i];
154 m_aPicklistVector.clear();
157 SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
159 OSL_ASSERT( m_aPicklistVector.size() > nIndex );
161 if ( nIndex < m_aPicklistVector.size() )
162 return m_aPicklistVector[ nIndex ];
163 else
164 return 0;
167 void SfxPickList::AddDocumentToPickList( SfxObjectShell* pDocSh )
169 SfxMedium *pMed = pDocSh->GetMedium();
170 if( !pMed )
171 return;
173 // Unnamed Documents and embedded-Documents not in Picklist
174 if ( !pDocSh->HasName() ||
175 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
176 return;
178 // Help not in History
179 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
180 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
181 return;
183 if ( !pMed->IsUpdatePickList() )
184 return;
186 // add no document that forbids this (for example Message-Body)
187 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
188 if ( pPicklistItem && !pPicklistItem->GetValue() )
189 return;
191 // ignore hidden documents
192 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
193 return;
195 ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
196 ::rtl::OUString aFilter;
197 const SfxFilter* pFilter = pMed->GetOrigFilter();
198 if ( pFilter )
199 aFilter = pFilter->GetFilterName();
201 // add to svtool history options
202 SvtHistoryOptions().AppendItem( ePICKLIST,
203 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
204 aFilter,
205 aTitle,
206 SfxStringEncode( aURL.GetPass() ) );
208 if ( aURL.GetProtocol() == INET_PROT_FILE )
209 Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ), (pFilter) ? pFilter->GetMimeType() : ::rtl::OUString() );
212 SfxPickList& SfxPickList::Get()
214 static SfxPickList aUniqueInstance(SvtHistoryOptions().GetSize(ePICKLIST));
215 return aUniqueInstance;
218 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
219 m_nAllowedMenuSize( nAllowedMenuSize )
221 m_xStringLength = new StringLength;
222 m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
223 StartListening( *SFX_APP() );
226 SfxPickList::~SfxPickList()
228 RemovePickListEntries();
231 void SfxPickList::CreatePickListEntries()
233 RemovePickListEntries();
235 // Reading the pick list
236 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
238 sal_uInt32 nCount = seqPicklist.getLength();
239 sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
241 for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
243 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
245 INetURLObject aURL;
246 ::rtl::OUString sURL;
247 ::rtl::OUString sFilter;
248 ::rtl::OUString sTitle;
249 ::rtl::OUString sPassword;
251 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
252 for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
254 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
256 seqPropertySet[nProperty].Value >>= sURL;
258 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
260 seqPropertySet[nProperty].Value >>= sFilter;
262 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
264 seqPropertySet[nProperty].Value >>= sTitle;
266 else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_PASSWORD )
268 seqPropertySet[nProperty].Value >>= sPassword;
272 aURL.SetSmartURL( sURL );
273 aURL.SetPass( SfxStringDecode( sPassword ) );
275 PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
276 m_aPicklistVector.push_back( pPick );
280 void SfxPickList::CreateMenuEntries( Menu* pMenu )
282 ::osl::MutexGuard aGuard( thePickListMutex::get() );
284 static sal_Bool bPickListMenuInitializing = sal_False;
286 if ( bPickListMenuInitializing ) // method is not reentrant!
287 return;
289 bPickListMenuInitializing = sal_True;
290 CreatePickListEntries();
292 for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
293 pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
295 if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
296 pMenu->RemoveItem( pMenu->GetItemCount()-1 );
298 if ( m_aPicklistVector.size() > 0 &&
299 pMenu->GetItemType( pMenu->GetItemCount()-1 )
300 != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
301 pMenu->InsertSeparator();
303 rtl::OUString aEmptyString;
304 for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
306 PickListEntry* pEntry = GetPickListEntry( i );
308 pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
309 CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
312 bPickListMenuInitializing = sal_False;
315 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
317 ::osl::ClearableMutexGuard aGuard( thePickListMutex::get() );
319 PickListEntry *pPick = SfxPickList::Get().GetPickListEntry( nIndex );
321 if ( pPick )
323 SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
324 aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
325 aReq.AppendItem( SfxStringItem( SID_REFERER, DEFINE_CONST_UNICODE( SFX_REFERER_USER ) ) );
326 aReq.AppendItem( SfxStringItem( SID_TARGETNAME, DEFINE_CONST_UNICODE("_default") ) );
327 String aFilter( pPick->aFilter );
328 aGuard.clear();
330 sal_uInt16 nPos=aFilter.Search('|');
331 if( nPos != STRING_NOTFOUND )
333 String aOptions(aFilter.Copy( nPos ).GetBuffer()+1);
334 aFilter.Erase( nPos );
335 aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
338 aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
339 aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
340 SFX_APP()->ExecuteSlot( aReq );
344 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
346 ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
349 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
351 if ( rHint.IsA( TYPE( SfxStringHint )))
353 SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
355 if ( pStringHint->GetId() == SID_OPENURL )
356 INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
359 if ( rHint.IsA( TYPE( SfxEventHint )))
361 SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
362 // only ObjectShell-related events with media interest
363 SfxObjectShell* pDocSh = pEventHint->GetObjShell();
364 if( !pDocSh )
365 return;
367 switch ( pEventHint->GetEventId() )
369 case SFX_EVENT_CREATEDOC:
371 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
372 if ( bAllowModif )
373 pDocSh->EnableSetModified( sal_False );
375 using namespace ::com::sun::star;
376 uno::Reference<document::XDocumentProperties> xDocProps(
377 pDocSh->getDocProperties());
378 if (xDocProps.is()) {
379 xDocProps->setAuthor( SvtUserOptions().GetFullName() );
380 ::DateTime now( ::DateTime::SYSTEM );
381 xDocProps->setCreationDate( util::DateTime(
382 now.Get100Sec(), now.GetSec(), now.GetMin(),
383 now.GetHour(), now.GetDay(), now.GetMonth(),
384 now.GetYear() ) );
387 if ( bAllowModif )
388 pDocSh->EnableSetModified( bAllowModif );
390 break;
392 case SFX_EVENT_OPENDOC:
394 SfxMedium *pMed = pDocSh->GetMedium();
395 if( !pMed )
396 return;
398 // Unnamed Documents and embedded-Documents not in History
399 if ( !pDocSh->HasName() ||
400 SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
401 return;
403 // Help not in History
404 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
405 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
406 return;
408 ::rtl::OUString aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
409 ::rtl::OUString aFilter;
410 const SfxFilter* pFilter = pMed->GetOrigFilter();
411 if ( pFilter )
412 aFilter = pFilter->GetFilterName();
414 // add to svtool history options
415 SvtHistoryOptions().AppendItem( eHISTORY,
416 aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
417 aFilter,
418 aTitle,
419 SfxStringEncode( aURL.GetPass() ) );
421 break;
423 case SFX_EVENT_SAVEDOCDONE:
424 case SFX_EVENT_SAVEASDOCDONE:
425 case SFX_EVENT_SAVETODOCDONE:
426 case SFX_EVENT_CLOSEDOC:
428 AddDocumentToPickList(pDocSh);
430 break;
432 case SFX_EVENT_SAVEASDOC:
434 SfxMedium *pMedium = pDocSh->GetMedium();
435 if (!pMedium)
436 return;
438 // We're starting a "Save As". Add the current document (if it's
439 // not a "new" document) to the "Recent Documents" list before we
440 // switch to the new path.
441 // If the current document is new, path will be empty.
442 rtl::OUString path = pMedium->GetOrigURL();
443 if (!path.isEmpty())
445 AddDocumentToPickList(pDocSh);
448 break;
453 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */