xref: /AOO41X/main/sfx2/source/appl/sfxpicklist.cxx (revision d119d52d53d0b2180f2ae51341d882123be2af2b)
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:
StringLength()74         StringLength() {}
~StringLength()75         virtual ~StringLength() {}
76 
77         // XStringWidth
queryStringWidth(const::rtl::OUString & aString)78         sal_Int32 SAL_CALL queryStringWidth( const ::rtl::OUString& aString )
79             throw (::com::sun::star::uno::RuntimeException)
80         {
81             return aString.getLength();
82         }
83 };
84 
85 // ----------------------------------------------------------------------------
86 
GetOrCreateMutex()87 osl::Mutex* SfxPickList::GetOrCreateMutex()
88 {
89     if ( !pMutex )
90     {
91         ::osl::MutexGuard aGuard( ::osl::Mutex::getGlobalMutex() );
92         if ( !pMutex )
93             pMutex = new osl::Mutex;
94     }
95 
96     return pMutex;
97 }
98 
CreatePicklistMenuTitle(Menu * pMenu,sal_uInt16 nItemId,const String & aURLString,sal_uInt32 nNo)99 void SfxPickList::CreatePicklistMenuTitle( Menu* pMenu, sal_uInt16 nItemId, const String& aURLString, sal_uInt32 nNo )
100 {
101     String aPickEntry;
102 
103     if ( nNo < 9 )
104     {
105         aPickEntry += '~';
106         aPickEntry += String::CreateFromInt32( nNo + 1 );
107     }
108     else if ( nNo == 9 )
109         aPickEntry += DEFINE_CONST_UNICODE("1~0");
110     else
111         aPickEntry += String::CreateFromInt32( nNo + 1 );
112     aPickEntry += DEFINE_CONST_UNICODE(": ");
113 
114     INetURLObject   aURL( aURLString );
115     rtl::OUString   aTipHelpText;
116     rtl::OUString   aAccessibleName( aPickEntry );
117 
118     if ( aURL.GetProtocol() == INET_PROT_FILE )
119     {
120         // Do handle file URL differently => convert it to a system
121         // path and abbreviate it with a special function:
122         String aFileSystemPath( aURL.getFSysPath( INetURLObject::FSYS_DETECT ) );
123 
124 //      ::utl::LocalFileHelper::ConvertURLToPhysicalName( aURLString, aPhysicalName );
125 
126         ::rtl::OUString aSystemPath( aFileSystemPath );
127         ::rtl::OUString aCompactedSystemPath;
128 
129         aTipHelpText = aSystemPath;
130         aAccessibleName += aSystemPath;
131         oslFileError nError = osl_abbreviateSystemPath( aSystemPath.pData, &aCompactedSystemPath.pData, 46, NULL );
132         if ( !nError )
133             aPickEntry += String( aCompactedSystemPath );
134         else
135             aPickEntry += aFileSystemPath;
136 
137         if ( aPickEntry.Len() > 50 )
138         {
139             aPickEntry.Erase( 47 );
140             aPickEntry += DEFINE_CONST_UNICODE("...");
141         }
142     }
143     else
144     {
145         // Use INetURLObject to abbreviate all other URLs
146         String  aShortURL;
147         aShortURL = aURL.getAbbreviated( m_xStringLength, 46, INetURLObject::DECODE_UNAMBIGUOUS );
148         aPickEntry += aShortURL;
149         aTipHelpText = aURLString;
150         aAccessibleName += aURLString;
151     }
152 
153     // Set menu item text, tip help and accessible name
154     pMenu->SetItemText( nItemId, aPickEntry );
155     pMenu->SetTipHelpText( nItemId, aTipHelpText );
156     pMenu->SetAccessibleName( nItemId, aAccessibleName );
157 }
158 
RemovePickListEntries()159 void SfxPickList::RemovePickListEntries()
160 {
161     ::osl::MutexGuard aGuard( GetOrCreateMutex() );
162     for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
163         delete m_aPicklistVector[i];
164     m_aPicklistVector.clear();
165 }
166 
GetPickListEntry(sal_uInt32 nIndex)167 SfxPickList::PickListEntry* SfxPickList::GetPickListEntry( sal_uInt32 nIndex )
168 {
169     OSL_ASSERT( m_aPicklistVector.size() > nIndex );
170 
171     if ( nIndex < m_aPicklistVector.size() )
172         return m_aPicklistVector[ nIndex ];
173     else
174         return 0;
175 }
176 
GetOrCreate(const sal_uInt32 nMenuSize)177 SfxPickList*    SfxPickList::GetOrCreate( const sal_uInt32 nMenuSize )
178 {
179     if ( !pUniqueInstance )
180     {
181         ::osl::MutexGuard aGuard( GetOrCreateMutex() );
182         if ( !pUniqueInstance )
183             pUniqueInstance = new SfxPickList( nMenuSize );
184     }
185 
186     return pUniqueInstance;
187 }
188 
Get()189 SfxPickList* SfxPickList::Get()
190 {
191     ::osl::MutexGuard aGuard( GetOrCreateMutex() );
192     return pUniqueInstance;
193 }
194 
Delete()195 void SfxPickList::Delete()
196 {
197     ::osl::MutexGuard aGuard( GetOrCreateMutex() );
198     DELETEZ( pUniqueInstance );
199 }
200 
SfxPickList(sal_uInt32 nAllowedMenuSize)201 SfxPickList::SfxPickList( sal_uInt32 nAllowedMenuSize ) :
202     m_nAllowedMenuSize( nAllowedMenuSize )
203 {
204     m_xStringLength = new StringLength;
205     m_nAllowedMenuSize = ::std::min( m_nAllowedMenuSize, (sal_uInt32)PICKLIST_MAXSIZE );
206     StartListening( *SFX_APP() );
207 }
208 
~SfxPickList()209 SfxPickList::~SfxPickList()
210 {
211     RemovePickListEntries();
212 }
213 
CreatePickListEntries()214 void SfxPickList::CreatePickListEntries()
215 {
216     RemovePickListEntries();
217 
218     // Einlesen der Pickliste
219     Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( ePICKLIST );
220 
221     sal_uInt32 nCount   = seqPicklist.getLength();
222     sal_uInt32 nEntries = ::std::min( m_nAllowedMenuSize, nCount );
223 
224     for( sal_uInt32 nItem=0; nItem < nEntries; ++nItem )
225     {
226         Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
227 
228         INetURLObject   aURL;
229         ::rtl::OUString sURL;
230         ::rtl::OUString sFilter;
231         ::rtl::OUString sTitle;
232         ::rtl::OUString sPassword;
233 
234         sal_uInt32 nPropertyCount = seqPropertySet.getLength();
235         for( sal_uInt32 nProperty=0; nProperty<nPropertyCount; ++nProperty )
236         {
237             if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
238             {
239                 seqPropertySet[nProperty].Value >>= sURL;
240             }
241             else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_FILTER )
242             {
243                 seqPropertySet[nProperty].Value >>= sFilter;
244             }
245             else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
246             {
247                 seqPropertySet[nProperty].Value >>= sTitle;
248             }
249             else if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_PASSWORD )
250             {
251                 seqPropertySet[nProperty].Value >>= sPassword;
252             }
253         }
254 
255         aURL.SetSmartURL( sURL );
256         aURL.SetPass( SfxStringDecode( sPassword ) );
257 
258         PickListEntry *pPick = new PickListEntry( aURL.GetMainURL( INetURLObject::NO_DECODE ), sFilter, sTitle );
259         m_aPicklistVector.push_back( pPick );
260     }
261 }
262 
CreateMenuEntries(Menu * pMenu)263 void SfxPickList::CreateMenuEntries( Menu* pMenu )
264 {
265     static sal_Bool bPickListMenuInitializing = sal_False;
266 
267     ::osl::MutexGuard aGuard( GetOrCreateMutex() );
268 
269     if ( bPickListMenuInitializing ) // method is not reentrant!
270         return;
271 
272     bPickListMenuInitializing = sal_True;
273     CreatePickListEntries();
274 
275     for ( sal_uInt16 nId = START_ITEMID_PICKLIST; nId <= END_ITEMID_PICKLIST; ++nId )
276         pMenu->RemoveItem( pMenu->GetItemPos( nId ) );
277 
278     if ( pMenu->GetItemType( pMenu->GetItemCount()-1 ) == MENUITEM_SEPARATOR )
279         pMenu->RemoveItem( pMenu->GetItemCount()-1 );
280 
281     if ( m_aPicklistVector.size() > 0 &&
282          pMenu->GetItemType( pMenu->GetItemCount()-1 )
283             != MENUITEM_SEPARATOR && m_nAllowedMenuSize )
284         pMenu->InsertSeparator();
285 
286     rtl::OUString aEmptyString;
287     for ( sal_uInt32 i = 0; i < m_aPicklistVector.size(); i++ )
288     {
289         PickListEntry* pEntry = GetPickListEntry( i );
290 
291         pMenu->InsertItem( (sal_uInt16)(START_ITEMID_PICKLIST + i), aEmptyString );
292         CreatePicklistMenuTitle( pMenu, (sal_uInt16)(START_ITEMID_PICKLIST + i), pEntry->aName, i );
293     }
294 
295     bPickListMenuInitializing = sal_False;
296 }
297 
ExecuteEntry(sal_uInt32 nIndex)298 void SfxPickList::ExecuteEntry( sal_uInt32 nIndex )
299 {
300     ::osl::ClearableMutexGuard aGuard( GetOrCreateMutex() );
301 
302     PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
303 
304     if ( pPick )
305     {
306         SfxRequest aReq( SID_OPENDOC, SFX_CALLMODE_ASYNCHRON, SFX_APP()->GetPool() );
307         aReq.AppendItem( SfxStringItem( SID_FILE_NAME, pPick->aName ));
308         aReq.AppendItem( SfxStringItem( SID_REFERER, DEFINE_CONST_UNICODE( SFX_REFERER_USER ) ) );
309         aReq.AppendItem( SfxStringItem( SID_TARGETNAME, DEFINE_CONST_UNICODE("_default") ) );
310         String aFilter( pPick->aFilter );
311         aGuard.clear();
312 
313         sal_uInt16 nPos=aFilter.Search('|');
314         if( nPos != STRING_NOTFOUND )
315         {
316             String aOptions(aFilter.Copy( nPos ).GetBuffer()+1);
317             aFilter.Erase( nPos );
318             aReq.AppendItem( SfxStringItem(SID_FILE_FILTEROPTIONS, aOptions));
319         }
320 
321         aReq.AppendItem(SfxStringItem( SID_FILTER_NAME, aFilter ));
322         aReq.AppendItem( SfxBoolItem( SID_TEMPLATE, sal_False ) );
323         SFX_APP()->ExecuteSlot( aReq );
324     }
325 }
326 
ExecuteMenuEntry(sal_uInt16 nId)327 void SfxPickList::ExecuteMenuEntry( sal_uInt16 nId )
328 {
329     ExecuteEntry( (sal_uInt32)( nId - START_ITEMID_PICKLIST ) );
330 }
331 
GetMenuEntryTitle(sal_uInt32 nIndex)332 String SfxPickList::GetMenuEntryTitle( sal_uInt32 nIndex )
333 {
334     PickListEntry *pPick = SfxPickList::Get()->GetPickListEntry( nIndex );
335 
336     if ( pPick )
337         return pPick->aTitle;
338     else
339         return String();
340 }
341 
Notify(SfxBroadcaster &,const SfxHint & rHint)342 void SfxPickList::Notify( SfxBroadcaster&, const SfxHint& rHint )
343 {
344     if ( rHint.IsA( TYPE( SfxStringHint )))
345     {
346         SfxStringHint* pStringHint = (SfxStringHint*) &rHint;
347 
348         if ( pStringHint->GetId() == SID_OPENURL )
349             INetURLHistory::GetOrCreate()->PutUrl( INetURLObject( pStringHint->GetObject() ));
350     }
351 
352     if ( rHint.IsA( TYPE( SfxEventHint )))
353     {
354         SfxEventHint* pEventHint = PTR_CAST(SfxEventHint,&rHint);
355         // nur ObjectShell-bezogene Events mit Medium interessieren
356         SfxObjectShell* pDocSh = pEventHint->GetObjShell();
357         if( !pDocSh )
358             return;
359 
360         switch ( pEventHint->GetEventId() )
361         {
362             case SFX_EVENT_CREATEDOC:
363             {
364                 sal_Bool bAllowModif = pDocSh->IsEnableSetModified();
365                 if ( bAllowModif )
366                     pDocSh->EnableSetModified( sal_False );
367 
368                 using namespace ::com::sun::star;
369                 uno::Reference<document::XDocumentProperties> xDocProps(
370                     pDocSh->getDocProperties());
371                 if (xDocProps.is()) {
372                     xDocProps->setAuthor( SvtUserOptions().GetFullName() );
373                     ::DateTime now;
374                     xDocProps->setCreationDate( util::DateTime(
375                         now.Get100Sec(), now.GetSec(), now.GetMin(),
376                         now.GetHour(), now.GetDay(), now.GetMonth(),
377                         now.GetYear() ) );
378                 }
379 
380                 if ( bAllowModif )
381                     pDocSh->EnableSetModified( bAllowModif );
382             }
383             break;
384 
385             case SFX_EVENT_OPENDOC:
386             {
387                 SfxMedium *pMed = pDocSh->GetMedium();
388                 if( !pMed )
389                     return;
390 
391                 // unbenannt-Docs und embedded-Docs nicht in History
392                 if ( !pDocSh->HasName() ||
393                      SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
394                     return;
395 
396                 // Hilfe nicht in History
397                 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
398                 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
399                     return;
400 
401                 ::rtl::OUString  aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
402                 ::rtl::OUString  aFilter;
403                 const SfxFilter* pFilter = pMed->GetOrigFilter();
404                 if ( pFilter )
405                     aFilter = pFilter->GetFilterName();
406 
407                 // add to svtool history options
408                 SvtHistoryOptions().AppendItem( eHISTORY,
409                         aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
410                         aFilter,
411                         aTitle,
412                         SfxStringEncode( aURL.GetPass() ) );
413             }
414             break;
415 
416             case SFX_EVENT_CLOSEDOC:
417             {
418                 SfxMedium *pMed = pDocSh->GetMedium();
419                 if( !pMed )
420                     return;
421 
422                 // unbenannt-Docs und embedded-Docs nicht in Pickliste
423                 if ( !pDocSh->HasName() ||
424                      SFX_CREATE_MODE_STANDARD != pDocSh->GetCreateMode() )
425                     return;
426 
427                 // Hilfe nicht in History
428                 INetURLObject aURL( pDocSh->IsDocShared() ? pDocSh->GetSharedFileURL() : ::rtl::OUString( pMed->GetOrigURL() ) );
429                 if ( aURL.GetProtocol() == INET_PROT_VND_SUN_STAR_HELP )
430                     return;
431 
432                 // only add r/w document into picklist
433                 if ( pDocSh->IsReadOnly() || !pMed->IsUpdatePickList() )
434                     return;
435 
436                 // add no document that forbids this (for example Message-Body)
437                 SFX_ITEMSET_ARG( pMed->GetItemSet(), pPicklistItem, SfxBoolItem, SID_PICKLIST, sal_False );
438                 if (
439                     (pPicklistItem && !pPicklistItem->GetValue()) ||
440                     (!(pDocSh->Get_Impl()->bWaitingForPicklist) )
441                    )
442                     return;
443 
444                 // ignore hidden documents
445                 if ( !SfxViewFrame::GetFirst( pDocSh, sal_True ) )
446                     return;
447 
448                 ::rtl::OUString  aTitle = pDocSh->GetTitle(SFX_TITLE_PICKLIST);
449                 ::rtl::OUString  aFilter;
450                 const SfxFilter* pFilter = pMed->GetOrigFilter();
451                 if ( pFilter )
452                     aFilter = pFilter->GetFilterName();
453 
454                 // add to svtool history options
455                 SvtHistoryOptions().AppendItem( ePICKLIST,
456                         aURL.GetURLNoPass( INetURLObject::NO_DECODE ),
457                         aFilter,
458                         aTitle,
459                         SfxStringEncode( aURL.GetPass() ) );
460 
461                 pDocSh->Get_Impl()->bWaitingForPicklist = sal_False;
462 
463                 if ( aURL.GetProtocol() == INET_PROT_FILE )
464                     Application::AddToRecentDocumentList( aURL.GetURLNoPass( INetURLObject::NO_DECODE ), (pFilter) ? pFilter->GetMimeType() : String() );
465             }
466             break;
467         }
468     }
469 }
470