xref: /trunk/main/sfx2/source/appl/sfxpicklist.cxx (revision 45c5a00162811bd03b87fcb4fe9996782f2b59ec) !
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