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