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