xref: /trunk/main/ucb/source/ucp/tdoc/tdoc_docmgr.cxx (revision 91144cd0085a7583d2099b982122deb2184ab956)
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_tdoc.hxx"
26 
27 /**************************************************************************
28                                 TODO
29  **************************************************************************
30 
31  *************************************************************************/
32 
33 #include "osl/diagnose.h"
34 #include "rtl/ref.hxx"
35 #include "cppuhelper/weak.hxx"
36 
37 #include "comphelper/namedvaluecollection.hxx"
38 #include "comphelper/documentinfo.hxx"
39 
40 #include "com/sun/star/awt/XTopWindow.hpp"
41 #include "com/sun/star/beans/XPropertySet.hpp"
42 #include "com/sun/star/container/XEnumerationAccess.hpp"
43 #include "com/sun/star/document/XStorageBasedDocument.hpp"
44 #include "com/sun/star/frame/XStorable.hpp"
45 #include "com/sun/star/lang/DisposedException.hpp"
46 #include "com/sun/star/util/XCloseBroadcaster.hpp"
47 
48 #include "tdoc_docmgr.hxx"
49 
50 using namespace com::sun::star;
51 using namespace tdoc_ucp;
52 using ::comphelper::DocumentInfo;
53 
54 //=========================================================================
55 //=========================================================================
56 //
57 // OfficeDocumentsCloseListener Implementation.
58 //
59 //=========================================================================
60 //=========================================================================
61 
62 //=========================================================================
63 //
64 // util::XCloseListener
65 //
66 //=========================================================================
67 
68 // virtual
queryClosing(const lang::EventObject &,sal_Bool)69 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::queryClosing(
70          const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
71 {
72 }
73 
74 //=========================================================================
notifyClosing(const lang::EventObject & Source)75 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::notifyClosing(
76          const lang::EventObject& Source )
77 {
78     document::EventObject aDocEvent;
79     aDocEvent.Source = Source.Source;
80     aDocEvent.EventName = rtl::OUString(
81         RTL_CONSTASCII_USTRINGPARAM( "OfficeDocumentsListener::notifyClosing" ) );
82     m_pManager->notifyEvent( aDocEvent );
83 }
84 
85 //=========================================================================
86 //
87 // lang::XEventListener (base of util::XCloseListener)
88 //
89 //=========================================================================
90 
91 // virtual
disposing(const lang::EventObject &)92 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::disposing(
93         const lang::EventObject& /*Source*/ )
94 {
95 }
96 
97 //=========================================================================
98 //=========================================================================
99 //
100 // OfficeDocumentsManager Implementation.
101 //
102 //=========================================================================
103 //=========================================================================
104 
OfficeDocumentsManager(const uno::Reference<lang::XMultiServiceFactory> & xSMgr,OfficeDocumentsEventListener * pDocEventListener)105 OfficeDocumentsManager::OfficeDocumentsManager(
106             const uno::Reference< lang::XMultiServiceFactory > & xSMgr,
107             OfficeDocumentsEventListener * pDocEventListener )
108 : m_xSMgr( xSMgr ),
109   m_xDocEvtNotifier( createDocumentEventNotifier( xSMgr ) ),
110   m_pDocEventListener( pDocEventListener ),
111   m_xDocCloseListener( new OfficeDocumentsCloseListener( this ) )
112 {
113     if ( m_xDocEvtNotifier.is() )
114     {
115         // Order is important (multithreaded environment)
116         m_xDocEvtNotifier->addEventListener( this );
117         buildDocumentsList();
118     }
119 }
120 
121 //=========================================================================
122 // virtual
~OfficeDocumentsManager()123 OfficeDocumentsManager::~OfficeDocumentsManager()
124 {
125     //OSL_ENSURE( m_aDocs.empty(), "document list not empty!" );
126     // no need to assert this: Normal shutdown of OOo could already trigger it, since the order in which
127     // objects are actually released/destroyed upon shutdown is not defined. And when we arrive *here*,
128     // OOo *is* shutting down currently, since we're held by the TDOC provider, which is disposed
129     // upon shutdown.
130 }
131 
132 //=========================================================================
destroy()133 void OfficeDocumentsManager::destroy()
134 {
135     if ( m_xDocEvtNotifier.is() )
136         m_xDocEvtNotifier->removeEventListener( this );
137 }
138 
139 //=========================================================================
140 static rtl::OUString
getDocumentId(const uno::Reference<uno::XInterface> & xDoc)141 getDocumentId( const uno::Reference< uno::XInterface > & xDoc )
142 {
143     rtl::OUString aId;
144 
145     // Try to get the UID directly from the document.
146     uno::Reference< beans::XPropertySet > xPropSet( xDoc, uno::UNO_QUERY );
147     if ( xPropSet.is() )
148     {
149         try
150         {
151             uno::Any aValue = xPropSet->getPropertyValue(
152                 rtl::OUString(
153                     RTL_CONSTASCII_USTRINGPARAM( "RuntimeUID" ) ) );
154             aValue >>= aId;
155         }
156         catch ( beans::UnknownPropertyException const & )
157         {
158             // Not actually an error. Property is optional.
159         }
160         catch ( lang::WrappedTargetException const & )
161         {
162             OSL_ENSURE( false, "Caught WrappedTargetException!" );
163         }
164     }
165 
166     if ( aId.getLength() == 0 )
167     {
168         // fallback: generate UID from document's this pointer.
169         // normalize the interface pointer first. Else, calls with different
170         // interfaces to the same object (say, XFoo and XBar) will produce
171         // different IDs
172         uno::Reference< uno::XInterface > xNormalizedIFace( xDoc, uno::UNO_QUERY );
173         sal_Int64 nId = reinterpret_cast< sal_Int64 >( xNormalizedIFace.get() );
174         aId = rtl::OUString::valueOf( nId );
175     }
176 
177     OSL_ENSURE( aId.getLength() > 0, "getDocumentId - Empty id!" );
178     return aId;
179 }
180 
181 //=========================================================================
182 //
183 // document::XEventListener
184 //
185 //=========================================================================
186 
187 // virtual
notifyEvent(const document::EventObject & Event)188 void SAL_CALL OfficeDocumentsManager::notifyEvent(
189         const document::EventObject & Event )
190 {
191 /*
192     Events documentation: OOo Developer's Guide / Writing UNO Components / Jobs
193 */
194 
195     if ( Event.EventName.equalsAsciiL(
196                 RTL_CONSTASCII_STRINGPARAM( "OnLoadFinished" ) ) // document loaded
197          || Event.EventName.equalsAsciiL(
198                 RTL_CONSTASCII_STRINGPARAM( "OnCreate" ) ) ) // document created
199     {
200         if ( isOfficeDocument( Event.Source ) )
201         {
202             osl::MutexGuard aGuard( m_aMtx );
203 
204             uno::Reference< frame::XModel >
205                  xModel( Event.Source, uno::UNO_QUERY );
206             OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
207 
208             DocumentList::const_iterator it = m_aDocs.begin();
209             while ( it != m_aDocs.end() )
210             {
211                 if ( (*it).second.xModel == xModel )
212                 {
213                     // already known.
214                     break;
215                 }
216                 ++it;
217             }
218 
219             if ( it == m_aDocs.end() )
220             {
221                 // new document
222 
223                 uno::Reference< document::XStorageBasedDocument >
224                     xDoc( Event.Source, uno::UNO_QUERY );
225                 OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
226 
227                 uno::Reference< embed::XStorage > xStorage
228                     = xDoc->getDocumentStorage();
229                 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
230 
231                 rtl:: OUString aDocId = getDocumentId( Event.Source );
232                 rtl:: OUString aTitle = DocumentInfo::getDocumentTitle(
233                     uno::Reference< frame::XModel >( Event.Source, uno::UNO_QUERY ) );
234 
235                 m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
236 
237                 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
238                     Event.Source, uno::UNO_QUERY );
239                 OSL_ENSURE( xCloseBroadcaster.is(),
240                     "OnLoadFinished/OnCreate event: got no close broadcaster!" );
241 
242                 if ( xCloseBroadcaster.is() )
243                     xCloseBroadcaster->addCloseListener( m_xDocCloseListener );
244 
245                 // Propagate document closure.
246                 OSL_ENSURE( m_pDocEventListener,
247                     "OnLoadFinished/OnCreate event: no owner for insert event propagation!" );
248 
249                 if ( m_pDocEventListener )
250                     m_pDocEventListener->notifyDocumentOpened( aDocId );
251             }
252         }
253     }
254     else if ( Event.EventName.equalsAsciiL(
255                 RTL_CONSTASCII_STRINGPARAM( "OfficeDocumentsListener::notifyClosing" ) ) )
256     {
257         if ( isOfficeDocument( Event.Source ) )
258         {
259             // Document has been closed (unloaded)
260 
261             // #163732# - Official event "OnUnload" does not work here. Event
262             // gets fired to early. Other OnUnload listeners called after this
263             // listener may still need TDOC access to the document. Remove the
264             // document from TDOC docs list on XCloseListener::notifyClosing.
265             // See OfficeDocumentsManager::OfficeDocumentsListener::notifyClosing.
266 
267             osl::MutexGuard aGuard( m_aMtx );
268 
269             uno::Reference< frame::XModel >
270                  xModel( Event.Source, uno::UNO_QUERY );
271             OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
272 
273             DocumentList::iterator it = m_aDocs.begin();
274             while ( it != m_aDocs.end() )
275             {
276                 if ( (*it).second.xModel == xModel )
277                 {
278                     // Propagate document closure.
279                     OSL_ENSURE( m_pDocEventListener,
280                         "OnUnload event: no owner for close event propagation!" );
281 
282                     if ( m_pDocEventListener )
283                     {
284                         rtl::OUString aDocId( (*it).first );
285                         m_pDocEventListener->notifyDocumentClosed( aDocId );
286                     }
287                     break;
288                 }
289                 ++it;
290             }
291 
292             OSL_ENSURE( it != m_aDocs.end(),
293                         "OnUnload event notified for unknown document!" );
294 
295             if ( it != m_aDocs.end() )
296             {
297                 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
298                     Event.Source, uno::UNO_QUERY );
299                 OSL_ENSURE( xCloseBroadcaster.is(),
300                     "OnUnload event: got no XCloseBroadcaster from XModel" );
301 
302                 if ( xCloseBroadcaster.is() )
303                     xCloseBroadcaster->removeCloseListener( m_xDocCloseListener );
304 
305                 m_aDocs.erase( it );
306             }
307         }
308     }
309     else if ( Event.EventName.equalsAsciiL(
310                 RTL_CONSTASCII_STRINGPARAM( "OnSaveDone" ) ) )
311     {
312         if ( isOfficeDocument( Event.Source ) )
313         {
314             osl::MutexGuard aGuard( m_aMtx );
315 
316             uno::Reference< frame::XModel >
317                  xModel( Event.Source, uno::UNO_QUERY );
318             OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
319 
320             DocumentList::iterator it = m_aDocs.begin();
321             while ( it != m_aDocs.end() )
322             {
323                 if ( (*it).second.xModel == xModel )
324                 {
325                     // Storage gets exchanged while saving.
326                     uno::Reference< document::XStorageBasedDocument >
327                         xDoc( Event.Source, uno::UNO_QUERY );
328                     OSL_ENSURE( xDoc.is(),
329                                 "Got no document::XStorageBasedDocument!" );
330 
331                     uno::Reference< embed::XStorage > xStorage
332                         = xDoc->getDocumentStorage();
333                     OSL_ENSURE( xStorage.is(), "Got no document storage!" );
334 
335                     (*it).second.xStorage = xStorage;
336                     break;
337                 }
338                 ++it;
339             }
340 
341             OSL_ENSURE( it != m_aDocs.end(),
342                         "OnSaveDone event notified for unknown document!" );
343         }
344     }
345     else if ( Event.EventName.equalsAsciiL(
346                 RTL_CONSTASCII_STRINGPARAM( "OnSaveAsDone" ) ) )
347     {
348         if ( isOfficeDocument( Event.Source ) )
349         {
350             osl::MutexGuard aGuard( m_aMtx );
351 
352             uno::Reference< frame::XModel >
353                  xModel( Event.Source, uno::UNO_QUERY );
354             OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
355 
356             DocumentList::iterator it = m_aDocs.begin();
357             while ( it != m_aDocs.end() )
358             {
359                 if ( (*it).second.xModel == xModel )
360                 {
361                     // Storage gets exchanged while saving.
362                     uno::Reference< document::XStorageBasedDocument >
363                         xDoc( Event.Source, uno::UNO_QUERY );
364                     OSL_ENSURE( xDoc.is(),
365                                 "Got no document::XStorageBasedDocument!" );
366 
367                     uno::Reference< embed::XStorage > xStorage
368                         = xDoc->getDocumentStorage();
369                     OSL_ENSURE( xStorage.is(), "Got no document storage!" );
370 
371                     (*it).second.xStorage = xStorage;
372 
373                     // Adjust title.
374                     (*it).second.aTitle = DocumentInfo::getDocumentTitle( xModel );
375                     break;
376                 }
377                 ++it;
378             }
379 
380             OSL_ENSURE( it != m_aDocs.end(),
381                         "OnSaveAsDone event notified for unknown document!" );
382         }
383     }
384     else if ( Event.EventName.equalsAsciiL(
385                 RTL_CONSTASCII_STRINGPARAM( "OnTitleChanged" ) ) )
386     {
387         if ( isOfficeDocument( Event.Source ) )
388         {
389             osl::MutexGuard aGuard( m_aMtx );
390 
391             uno::Reference< frame::XModel >
392                  xModel( Event.Source, uno::UNO_QUERY );
393             OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
394 
395             DocumentList::iterator it = m_aDocs.begin();
396             while ( it != m_aDocs.end() )
397             {
398                 if ( (*it).second.xModel == xModel )
399                 {
400                     // Adjust title.
401                     rtl:: OUString aTitle = DocumentInfo::getDocumentTitle( xModel );
402                     (*it).second.aTitle = aTitle;
403 
404                     // Adjust storage.
405                     uno::Reference< document::XStorageBasedDocument >
406                         xDoc( Event.Source, uno::UNO_QUERY );
407                     OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
408 
409                     uno::Reference< embed::XStorage > xStorage
410                         = xDoc->getDocumentStorage();
411                     OSL_ENSURE( xDoc.is(), "Got no document storage!" );
412 
413                     rtl:: OUString aDocId = getDocumentId( Event.Source );
414 
415                     m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
416                     break;
417                 }
418                 ++it;
419             }
420 
421 //            OSL_ENSURE( it != m_aDocs.end(),
422 //                        "TitleChanged event notified for unknown document!" );
423             // TODO: re-enable this assertion. It has been disabled for now, since it breaks the assertion-free smoketest,
424             // and the fix is more difficult than what can be done now.
425             // The problem is that at the moment, when you close a SFX-based document via API, it will first
426             // fire the notifyClosing event, which will make the OfficeDocumentsManager remove the doc from its list.
427             // Then, it will notify an OnTitleChanged, then an OnUnload. Documents closed via call the notifyClosing
428             // *after* OnUnload and all other On* events.
429             // In agreement with MBA, the implementation for SfxBaseModel::Close should be changed to also send notifyClosing
430             // as last event. When this happens, the assertion here must be enabled, again.
431             // There is no bug for this, yet - IZ is currently down due to the Kenai migration.
432             // 2011-02-23 / frank.schoenheit@sun.com
433         }
434     }
435 }
436 
437 //=========================================================================
438 //
439 // lang::XEventListener (base of document::XEventListener)
440 //
441 //=========================================================================
442 
443 // virtual
disposing(const lang::EventObject &)444 void SAL_CALL OfficeDocumentsManager::disposing(
445         const lang::EventObject& /*Source*/ )
446 {
447 }
448 
449 //=========================================================================
450 //
451 // Non-interface.
452 //
453 //=========================================================================
454 
455 // static
456 uno::Reference< document::XEventBroadcaster >
createDocumentEventNotifier(const uno::Reference<lang::XMultiServiceFactory> & rXSMgr)457 OfficeDocumentsManager::createDocumentEventNotifier(
458         const uno::Reference< lang::XMultiServiceFactory >& rXSMgr )
459 {
460     uno::Reference< uno::XInterface > xIfc;
461     try
462     {
463         xIfc = rXSMgr->createInstance(
464             rtl::OUString(
465                 RTL_CONSTASCII_USTRINGPARAM(
466                     "com.sun.star.frame.GlobalEventBroadcaster" ) ) );
467     }
468     catch ( uno::Exception const & )
469     {
470         // handled below.
471     }
472 
473     OSL_ENSURE(
474         xIfc.is(),
475         "Could not instantiate com.sun.star.frame.GlobalEventBroadcaster" );
476 
477     if ( xIfc.is() )
478     {
479         uno::Reference< document::XEventBroadcaster > xBC(
480             xIfc, uno::UNO_QUERY );
481 
482         OSL_ENSURE(
483             xBC.is(),
484             "com.sun.star.frame.GlobalEventBroadcaster does not implement "
485             "interface com.sun.star.document.XEventBroadcaster!" );
486 
487         return xBC;
488     }
489     else
490         return uno::Reference< document::XEventBroadcaster >();
491 }
492 
493 //=========================================================================
buildDocumentsList()494 void OfficeDocumentsManager::buildDocumentsList()
495 {
496     OSL_ENSURE( m_xDocEvtNotifier.is(),
497                 "OfficeDocumentsManager::buildDocumentsList - "
498                 "No document event notifier!" );
499 
500     uno::Reference< container::XEnumerationAccess > xEnumAccess(
501         m_xDocEvtNotifier, uno::UNO_QUERY_THROW );
502 
503     uno::Reference< container::XEnumeration > xEnum
504         = xEnumAccess->createEnumeration();
505 
506     osl::MutexGuard aGuard( m_aMtx );
507 
508     while ( xEnum->hasMoreElements() )
509     {
510         uno::Any aValue = xEnum->nextElement();
511         // container::NoSuchElementException
512         // lang::WrappedTargetException
513 
514         try
515         {
516             uno::Reference< frame::XModel > xModel;
517             aValue >>= xModel;
518 
519             if ( xModel.is() )
520             {
521                 if ( isOfficeDocument( xModel ) )
522                 {
523                     DocumentList::const_iterator it = m_aDocs.begin();
524                     while ( it != m_aDocs.end() )
525                     {
526                         if ( (*it).second.xModel == xModel )
527                         {
528                             // already known.
529                             break;
530                         }
531                         ++it;
532                     }
533 
534                     if ( it == m_aDocs.end() )
535                     {
536                         // new document
537                         rtl::OUString aDocId = getDocumentId( xModel );
538                         rtl::OUString aTitle = DocumentInfo::getDocumentTitle( xModel );
539 
540                         uno::Reference< document::XStorageBasedDocument >
541                                 xDoc( xModel, uno::UNO_QUERY );
542                         OSL_ENSURE( xDoc.is(),
543                             "Got no document::XStorageBasedDocument!" );
544 
545                         uno::Reference< embed::XStorage > xStorage
546                             = xDoc->getDocumentStorage();
547                         OSL_ENSURE( xDoc.is(), "Got no document storage!" );
548 
549                         m_aDocs[ aDocId ]
550                             = StorageInfo( aTitle, xStorage, xModel );
551 
552                         uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
553                             xModel, uno::UNO_QUERY );
554                         OSL_ENSURE( xCloseBroadcaster.is(),
555                             "buildDocumentsList: got no close broadcaster!" );
556 
557                         if ( xCloseBroadcaster.is() )
558                             xCloseBroadcaster->addCloseListener( m_xDocCloseListener );
559                     }
560                 }
561             }
562         }
563         catch ( lang::DisposedException const & )
564         {
565             // Note: Due to race conditions the XEnumeration can
566             //       contains docs that already have been closed
567         }
568     }
569 }
570 
571 //=========================================================================
572 uno::Reference< embed::XStorage >
queryStorage(const rtl::OUString & rDocId)573 OfficeDocumentsManager::queryStorage( const rtl::OUString & rDocId )
574 {
575     osl::MutexGuard aGuard( m_aMtx );
576 
577     DocumentList::const_iterator it = m_aDocs.find( rDocId );
578     if ( it == m_aDocs.end() )
579         return uno::Reference< embed::XStorage >();
580 
581     return (*it).second.xStorage;
582 }
583 
584 //=========================================================================
queryDocumentId(const uno::Reference<frame::XModel> & xModel)585 rtl::OUString OfficeDocumentsManager::queryDocumentId(
586     const uno::Reference< frame::XModel > & xModel )
587 {
588     return getDocumentId( xModel );
589 }
590 
591 //=========================================================================
592 uno::Reference< frame::XModel >
queryDocumentModel(const rtl::OUString & rDocId)593 OfficeDocumentsManager::queryDocumentModel( const rtl::OUString & rDocId )
594 {
595     osl::MutexGuard aGuard( m_aMtx );
596 
597     DocumentList::const_iterator it = m_aDocs.find( rDocId );
598     if ( it == m_aDocs.end() )
599         return uno::Reference< frame::XModel >();
600 
601     return (*it).second.xModel;
602 }
603 
604 //=========================================================================
queryDocuments()605 uno::Sequence< rtl::OUString > OfficeDocumentsManager::queryDocuments()
606 {
607     osl::MutexGuard aGuard( m_aMtx );
608 
609     uno::Sequence< rtl::OUString > aRet( m_aDocs.size() );
610     sal_Int32 nPos = 0;
611 
612     DocumentList::const_iterator it = m_aDocs.begin();
613     while ( it != m_aDocs.end() )
614     {
615         aRet[ nPos ] = (*it).first;
616         ++it;
617         ++nPos;
618     }
619     return aRet;
620 }
621 
622 //=========================================================================
623 rtl::OUString
queryStorageTitle(const rtl::OUString & rDocId)624 OfficeDocumentsManager::queryStorageTitle( const rtl::OUString & rDocId )
625 {
626     osl::MutexGuard aGuard( m_aMtx );
627 
628     DocumentList::const_iterator it = m_aDocs.find( rDocId );
629     if ( it == m_aDocs.end() )
630         return rtl::OUString();
631 
632     return (*it).second.aTitle;
633 }
634 
635 //=========================================================================
isDocumentPreview(const uno::Reference<frame::XModel> & xModel)636 bool OfficeDocumentsManager::isDocumentPreview(
637         const uno::Reference< frame::XModel > & xModel )
638 {
639     if ( !xModel.is() )
640         return false;
641 
642     ::comphelper::NamedValueCollection aArgs(
643         xModel->getArgs() );
644     sal_Bool bIsPreview = aArgs.getOrDefault( "Preview", sal_False );
645     return bIsPreview;
646 }
647 
648 //=========================================================================
isHelpDocument(const uno::Reference<frame::XModel> & xModel)649 bool OfficeDocumentsManager::isHelpDocument(
650         const uno::Reference< frame::XModel > & xModel )
651 {
652     if ( !xModel.is() )
653         return false;
654 
655     ::rtl::OUString sURL( xModel->getURL() );
656     if ( sURL.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.help://" ) ) )
657         return true;
658 
659     return false;
660 }
661 
662 //=========================================================================
isWithoutOrInTopLevelFrame(const uno::Reference<frame::XModel> & xModel)663 bool OfficeDocumentsManager::isWithoutOrInTopLevelFrame(
664         const uno::Reference< frame::XModel > & xModel )
665 {
666     if ( !xModel.is() )
667         return false;
668 
669     uno::Reference< frame::XController > xController
670         = xModel->getCurrentController();
671     if ( xController.is() )
672     {
673         uno::Reference< frame::XFrame > xFrame
674             = xController->getFrame();
675         if ( xFrame.is() )
676         {
677             // don't use XFrame::isTop here. This nowadays excludes
678             // "sub documents" such as forms embedded in database documents
679             uno::Reference< awt::XTopWindow > xFrameContainer(
680                 xFrame->getContainerWindow(), uno::UNO_QUERY );
681             if ( !xFrameContainer.is() )
682                 return false;
683         }
684     }
685 
686     return true;
687 }
688 
689 //=========================================================================
isBasicIDE(const uno::Reference<frame::XModel> & xModel)690 bool OfficeDocumentsManager::isBasicIDE(
691         const uno::Reference< frame::XModel > & xModel )
692 {
693     if ( !m_xModuleMgr.is() )
694     {
695         osl::MutexGuard aGuard( m_aMtx );
696         if ( !m_xModuleMgr.is() )
697         {
698             try
699             {
700                 m_xModuleMgr
701                     = uno::Reference<
702                         frame::XModuleManager >(
703                             m_xSMgr->createInstance(
704                                 rtl::OUString(
705                                     RTL_CONSTASCII_USTRINGPARAM(
706                                         "com.sun.star.frame.ModuleManager" ) ) ),
707                             uno::UNO_QUERY );
708             }
709             catch ( uno::Exception const & )
710             {
711                 // handled below.
712             }
713 
714             OSL_ENSURE( m_xModuleMgr .is(),
715                         "Could not instantiate ModuleManager service!" );
716         }
717     }
718 
719     if ( m_xModuleMgr.is() )
720     {
721         rtl::OUString aModule;
722         try
723         {
724             aModule = m_xModuleMgr->identify( xModel );
725         }
726         catch ( lang::IllegalArgumentException const & )
727         {
728             OSL_ENSURE( false, "Caught IllegalArgumentException!" );
729         }
730         catch ( frame::UnknownModuleException const & )
731         {
732             OSL_ENSURE( false, "Caught UnknownModuleException!" );
733         }
734 
735         if ( aModule.getLength() > 0 )
736         {
737             // Filter unwanted items, that are no real documents.
738             if ( aModule.equalsAsciiL( RTL_CONSTASCII_STRINGPARAM(
739                     "com.sun.star.script.BasicIDE" ) ) )
740             {
741                 return true;
742             }
743         }
744     }
745 
746     return false;
747 }
748 
749 //=========================================================================
isOfficeDocument(const uno::Reference<uno::XInterface> & xDoc)750 bool OfficeDocumentsManager::isOfficeDocument(
751         const uno::Reference< uno::XInterface > & xDoc )
752 {
753     uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
754     uno::Reference< document::XStorageBasedDocument >
755         xStorageBasedDoc( xModel, uno::UNO_QUERY );
756     if ( !xStorageBasedDoc.is() )
757         return false;
758 
759     if ( !isWithoutOrInTopLevelFrame( xModel ) )
760         return false;
761 
762     if ( isDocumentPreview( xModel ) )
763         return false;
764 
765     if ( isHelpDocument( xModel ) )
766         return false;
767 
768     if ( isBasicIDE( xModel ) )
769         return false;
770 
771     return true;
772 }
773