Bump for 3.6-28
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_docmgr.cxx
blob6bd7063b178c4515cdfc7c03238a04e24a46ce68
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*************************************************************************
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * Copyright 2000, 2010 Oracle and/or its affiliates.
8 * OpenOffice.org - a multi-platform office productivity suite
10 * This file is part of OpenOffice.org.
12 * OpenOffice.org is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU Lesser General Public License version 3
14 * only, as published by the Free Software Foundation.
16 * OpenOffice.org is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU Lesser General Public License version 3 for more details
20 * (a copy is included in the LICENSE file that accompanied this code).
22 * You should have received a copy of the GNU Lesser General Public License
23 * version 3 along with OpenOffice.org. If not, see
24 * <http://www.openoffice.org/license.html>
25 * for a copy of the LGPLv3 License.
27 ************************************************************************/
30 /**************************************************************************
31 TODO
32 **************************************************************************
34 *************************************************************************/
36 #include "osl/diagnose.h"
37 #include "rtl/ref.hxx"
38 #include "cppuhelper/weak.hxx"
40 #include "comphelper/namedvaluecollection.hxx"
41 #include "comphelper/documentinfo.hxx"
43 #include "com/sun/star/awt/XTopWindow.hpp"
44 #include "com/sun/star/beans/XPropertySet.hpp"
45 #include "com/sun/star/container/XEnumerationAccess.hpp"
46 #include "com/sun/star/document/XStorageBasedDocument.hpp"
47 #include "com/sun/star/frame/XStorable.hpp"
48 #include "com/sun/star/lang/DisposedException.hpp"
49 #include "com/sun/star/util/XCloseBroadcaster.hpp"
51 #include "tdoc_docmgr.hxx"
53 using namespace com::sun::star;
54 using namespace tdoc_ucp;
55 using ::comphelper::DocumentInfo;
57 //=========================================================================
58 //=========================================================================
60 // OfficeDocumentsCloseListener Implementation.
62 //=========================================================================
63 //=========================================================================
65 //=========================================================================
67 // util::XCloseListener
69 //=========================================================================
71 // virtual
72 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::queryClosing(
73 const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
74 throw ( util::CloseVetoException,
75 uno::RuntimeException )
79 //=========================================================================
80 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::notifyClosing(
81 const lang::EventObject& Source )
82 throw ( uno::RuntimeException )
84 document::EventObject aDocEvent;
85 aDocEvent.Source = Source.Source;
86 aDocEvent.EventName = rtl::OUString(
87 RTL_CONSTASCII_USTRINGPARAM( "OfficeDocumentsListener::notifyClosing" ) );
88 m_pManager->notifyEvent( aDocEvent );
91 //=========================================================================
93 // lang::XEventListener (base of util::XCloseListener)
95 //=========================================================================
97 // virtual
98 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::disposing(
99 const lang::EventObject& /*Source*/ )
100 throw ( uno::RuntimeException )
104 //=========================================================================
105 //=========================================================================
107 // OfficeDocumentsManager Implementation.
109 //=========================================================================
110 //=========================================================================
112 OfficeDocumentsManager::OfficeDocumentsManager(
113 const uno::Reference< lang::XMultiServiceFactory > & xSMgr,
114 OfficeDocumentsEventListener * pDocEventListener )
115 : m_xSMgr( xSMgr ),
116 m_xDocEvtNotifier( createDocumentEventNotifier( xSMgr ) ),
117 m_pDocEventListener( pDocEventListener ),
118 m_xDocCloseListener( new OfficeDocumentsCloseListener( this ) )
120 if ( m_xDocEvtNotifier.is() )
122 // Order is important (multithreaded environment)
123 m_xDocEvtNotifier->addEventListener( this );
124 buildDocumentsList();
128 //=========================================================================
129 // virtual
130 OfficeDocumentsManager::~OfficeDocumentsManager()
132 //OSL_ENSURE( m_aDocs.empty(), "document list not empty!" );
133 // no need to assert this: Normal shutdown of OOo could already trigger it, since the order in which
134 // objects are actually released/destroyed upon shutdown is not defined. And when we arrive *here*,
135 // OOo *is* shutting down currently, since we're held by the TDOC provider, which is disposed
136 // upon shutdown.
139 //=========================================================================
140 void OfficeDocumentsManager::destroy()
142 if ( m_xDocEvtNotifier.is() )
143 m_xDocEvtNotifier->removeEventListener( this );
146 //=========================================================================
147 static rtl::OUString
148 getDocumentId( const uno::Reference< uno::XInterface > & xDoc )
150 rtl::OUString aId;
152 // Try to get the UID directly from the document.
153 uno::Reference< beans::XPropertySet > xPropSet( xDoc, uno::UNO_QUERY );
154 if ( xPropSet.is() )
158 uno::Any aValue = xPropSet->getPropertyValue(
159 rtl::OUString(
160 RTL_CONSTASCII_USTRINGPARAM( "RuntimeUID" ) ) );
161 aValue >>= aId;
163 catch ( beans::UnknownPropertyException const & )
165 // Not actually an error. Property is optional.
167 catch ( lang::WrappedTargetException const & )
169 OSL_FAIL( "Caught WrappedTargetException!" );
173 if ( aId.isEmpty() )
175 // fallback: generate UID from document's this pointer.
176 // normalize the interface pointer first. Else, calls with different
177 // interfaces to the same object (say, XFoo and XBar) will produce
178 // different IDs
179 uno::Reference< uno::XInterface > xNormalizedIFace( xDoc, uno::UNO_QUERY );
180 sal_Int64 nId = reinterpret_cast< sal_Int64 >( xNormalizedIFace.get() );
181 aId = rtl::OUString::valueOf( nId );
184 OSL_ENSURE( !aId.isEmpty(), "getDocumentId - Empty id!" );
185 return aId;
188 //=========================================================================
190 // document::XEventListener
192 //=========================================================================
194 // virtual
195 void SAL_CALL OfficeDocumentsManager::notifyEvent(
196 const document::EventObject & Event )
197 throw ( uno::RuntimeException )
200 Events documentation: OOo Developer's Guide / Writing UNO Components / Jobs
203 if ( Event.EventName == "OnLoadFinished" // document loaded
204 || Event.EventName == "OnCreate" ) // document created
206 if ( isOfficeDocument( Event.Source ) )
208 osl::MutexGuard aGuard( m_aMtx );
210 uno::Reference< frame::XModel >
211 xModel( Event.Source, uno::UNO_QUERY );
212 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
214 DocumentList::const_iterator it = m_aDocs.begin();
215 while ( it != m_aDocs.end() )
217 if ( (*it).second.xModel == xModel )
219 // already known.
220 break;
222 ++it;
225 if ( it == m_aDocs.end() )
227 // new document
229 uno::Reference< document::XStorageBasedDocument >
230 xDoc( Event.Source, uno::UNO_QUERY );
231 OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
233 uno::Reference< embed::XStorage > xStorage
234 = xDoc->getDocumentStorage();
235 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
237 rtl:: OUString aDocId = getDocumentId( Event.Source );
238 rtl:: OUString aTitle = DocumentInfo::getDocumentTitle(
239 uno::Reference< frame::XModel >( Event.Source, uno::UNO_QUERY ) );
241 m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
243 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
244 Event.Source, uno::UNO_QUERY );
245 OSL_ENSURE( xCloseBroadcaster.is(),
246 "OnLoadFinished/OnCreate event: got no close broadcaster!" );
248 if ( xCloseBroadcaster.is() )
249 xCloseBroadcaster->addCloseListener( m_xDocCloseListener );
251 // Propagate document closure.
252 OSL_ENSURE( m_pDocEventListener,
253 "OnLoadFinished/OnCreate event: no owner for insert event propagation!" );
255 if ( m_pDocEventListener )
256 m_pDocEventListener->notifyDocumentOpened( aDocId );
260 else if ( Event.EventName == "OfficeDocumentsListener::notifyClosing" )
262 if ( isOfficeDocument( Event.Source ) )
264 // Document has been closed (unloaded)
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.
272 osl::MutexGuard aGuard( m_aMtx );
274 uno::Reference< frame::XModel >
275 xModel( Event.Source, uno::UNO_QUERY );
276 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
278 DocumentList::iterator it = m_aDocs.begin();
279 while ( it != m_aDocs.end() )
281 if ( (*it).second.xModel == xModel )
283 // Propagate document closure.
284 OSL_ENSURE( m_pDocEventListener,
285 "OnUnload event: no owner for close event propagation!" );
287 if ( m_pDocEventListener )
289 rtl::OUString aDocId( (*it).first );
290 m_pDocEventListener->notifyDocumentClosed( aDocId );
292 break;
294 ++it;
297 OSL_ENSURE( it != m_aDocs.end(),
298 "OnUnload event notified for unknown document!" );
300 if ( it != m_aDocs.end() )
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" );
307 if ( xCloseBroadcaster.is() )
308 xCloseBroadcaster->removeCloseListener( m_xDocCloseListener );
310 m_aDocs.erase( it );
314 else if ( Event.EventName == "OnSaveDone" )
316 if ( isOfficeDocument( Event.Source ) )
318 osl::MutexGuard aGuard( m_aMtx );
320 uno::Reference< frame::XModel >
321 xModel( Event.Source, uno::UNO_QUERY );
322 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
324 DocumentList::iterator it = m_aDocs.begin();
325 while ( it != m_aDocs.end() )
327 if ( (*it).second.xModel == xModel )
329 // Storage gets exchanged while saving.
330 uno::Reference< document::XStorageBasedDocument >
331 xDoc( Event.Source, uno::UNO_QUERY );
332 OSL_ENSURE( xDoc.is(),
333 "Got no document::XStorageBasedDocument!" );
335 uno::Reference< embed::XStorage > xStorage
336 = xDoc->getDocumentStorage();
337 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
339 (*it).second.xStorage = xStorage;
340 break;
342 ++it;
345 OSL_ENSURE( it != m_aDocs.end(),
346 "OnSaveDone event notified for unknown document!" );
349 else if ( Event.EventName == "OnSaveAsDone" )
351 if ( isOfficeDocument( Event.Source ) )
353 osl::MutexGuard aGuard( m_aMtx );
355 uno::Reference< frame::XModel >
356 xModel( Event.Source, uno::UNO_QUERY );
357 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
359 DocumentList::iterator it = m_aDocs.begin();
360 while ( it != m_aDocs.end() )
362 if ( (*it).second.xModel == xModel )
364 // Storage gets exchanged while saving.
365 uno::Reference< document::XStorageBasedDocument >
366 xDoc( Event.Source, uno::UNO_QUERY );
367 OSL_ENSURE( xDoc.is(),
368 "Got no document::XStorageBasedDocument!" );
370 uno::Reference< embed::XStorage > xStorage
371 = xDoc->getDocumentStorage();
372 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
374 (*it).second.xStorage = xStorage;
376 // Adjust title.
377 (*it).second.aTitle = DocumentInfo::getDocumentTitle( xModel );
378 break;
380 ++it;
383 OSL_ENSURE( it != m_aDocs.end(),
384 "OnSaveAsDone event notified for unknown document!" );
387 else if ( Event.EventName == "OnTitleChanged" )
389 if ( isOfficeDocument( Event.Source ) )
391 osl::MutexGuard aGuard( m_aMtx );
393 uno::Reference< frame::XModel >
394 xModel( Event.Source, uno::UNO_QUERY );
395 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
397 DocumentList::iterator it = m_aDocs.begin();
398 while ( it != m_aDocs.end() )
400 if ( (*it).second.xModel == xModel )
402 // Adjust title.
403 rtl:: OUString aTitle = DocumentInfo::getDocumentTitle( xModel );
404 (*it).second.aTitle = aTitle;
406 // Adjust storage.
407 uno::Reference< document::XStorageBasedDocument >
408 xDoc( Event.Source, uno::UNO_QUERY );
409 OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
411 uno::Reference< embed::XStorage > xStorage
412 = xDoc->getDocumentStorage();
413 OSL_ENSURE( xDoc.is(), "Got no document storage!" );
415 rtl:: OUString aDocId = getDocumentId( Event.Source );
417 m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
418 break;
420 ++it;
423 // OSL_ENSURE( it != m_aDocs.end(),
424 // "TitleChanged event notified for unknown document!" );
425 // TODO: re-enable this assertion. It has been disabled for now, since it breaks the assertion-free smoketest,
426 // and the fix is more difficult than what can be done now.
427 // The problem is that at the moment, when you close a SFX-based document via API, it will first
428 // fire the notifyClosing event, which will make the OfficeDocumentsManager remove the doc from its list.
429 // Then, it will notify an OnTitleChanged, then an OnUnload. Documents closed via call the notifyClosing
430 // *after* OnUnload and all other On* events.
431 // In agreement with MBA, the implementation for SfxBaseModel::Close should be changed to also send notifyClosing
432 // as last event. When this happens, the assertion here must be enabled, again.
433 // There is no bug for this, yet - IZ is currently down due to the Kenai migration.
434 // 2011-02-23 / frank.schoenheit@sun.com
439 //=========================================================================
441 // lang::XEventListener (base of document::XEventListener)
443 //=========================================================================
445 // virtual
446 void SAL_CALL OfficeDocumentsManager::disposing(
447 const lang::EventObject& /*Source*/ )
448 throw ( uno::RuntimeException )
452 //=========================================================================
454 // Non-interface.
456 //=========================================================================
458 // static
459 uno::Reference< document::XEventBroadcaster >
460 OfficeDocumentsManager::createDocumentEventNotifier(
461 const uno::Reference< lang::XMultiServiceFactory >& rXSMgr )
463 uno::Reference< uno::XInterface > xIfc;
466 xIfc = rXSMgr->createInstance(
467 rtl::OUString(
468 RTL_CONSTASCII_USTRINGPARAM(
469 "com.sun.star.frame.GlobalEventBroadcaster" ) ) );
471 catch ( uno::Exception const & )
473 // handled below.
476 OSL_ENSURE(
477 xIfc.is(),
478 "Could not instanciate com.sun.star.frame.GlobalEventBroadcaster" );
480 if ( xIfc.is() )
482 uno::Reference< document::XEventBroadcaster > xBC(
483 xIfc, uno::UNO_QUERY );
485 OSL_ENSURE(
486 xBC.is(),
487 "com.sun.star.frame.GlobalEventBroadcaster does not implement "
488 "interface com.sun.star.document.XEventBroadcaster!" );
490 return xBC;
492 else
493 return uno::Reference< document::XEventBroadcaster >();
496 //=========================================================================
497 void OfficeDocumentsManager::buildDocumentsList()
499 OSL_ENSURE( m_xDocEvtNotifier.is(),
500 "OfficeDocumentsManager::buildDocumentsList - "
501 "No document event notifier!" );
503 uno::Reference< container::XEnumerationAccess > xEnumAccess(
504 m_xDocEvtNotifier, uno::UNO_QUERY_THROW );
506 uno::Reference< container::XEnumeration > xEnum
507 = xEnumAccess->createEnumeration();
509 osl::MutexGuard aGuard( m_aMtx );
511 while ( xEnum->hasMoreElements() )
513 uno::Any aValue = xEnum->nextElement();
514 // container::NoSuchElementException
515 // lang::WrappedTargetException
519 uno::Reference< frame::XModel > xModel;
520 aValue >>= xModel;
522 if ( xModel.is() )
524 if ( isOfficeDocument( xModel ) )
526 DocumentList::const_iterator it = m_aDocs.begin();
527 while ( it != m_aDocs.end() )
529 if ( (*it).second.xModel == xModel )
531 // already known.
532 break;
534 ++it;
537 if ( it == m_aDocs.end() )
539 // new document
540 rtl::OUString aDocId = getDocumentId( xModel );
541 rtl::OUString aTitle = DocumentInfo::getDocumentTitle( xModel );
543 uno::Reference< document::XStorageBasedDocument >
544 xDoc( xModel, uno::UNO_QUERY );
545 OSL_ENSURE( xDoc.is(),
546 "Got no document::XStorageBasedDocument!" );
548 uno::Reference< embed::XStorage > xStorage
549 = xDoc->getDocumentStorage();
550 OSL_ENSURE( xDoc.is(), "Got no document storage!" );
552 m_aDocs[ aDocId ]
553 = StorageInfo( aTitle, xStorage, xModel );
555 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
556 xModel, uno::UNO_QUERY );
557 OSL_ENSURE( xCloseBroadcaster.is(),
558 "buildDocumentsList: got no close broadcaster!" );
560 if ( xCloseBroadcaster.is() )
561 xCloseBroadcaster->addCloseListener( m_xDocCloseListener );
566 catch ( lang::DisposedException const & )
568 // Note: Due to race conditions the XEnumeration can
569 // contains docs that already have been closed
574 //=========================================================================
575 uno::Reference< embed::XStorage >
576 OfficeDocumentsManager::queryStorage( const rtl::OUString & rDocId )
578 osl::MutexGuard aGuard( m_aMtx );
580 DocumentList::const_iterator it = m_aDocs.find( rDocId );
581 if ( it == m_aDocs.end() )
582 return uno::Reference< embed::XStorage >();
584 return (*it).second.xStorage;
587 //=========================================================================
588 rtl::OUString OfficeDocumentsManager::queryDocumentId(
589 const uno::Reference< frame::XModel > & xModel )
591 return getDocumentId( xModel );
594 //=========================================================================
595 uno::Reference< frame::XModel >
596 OfficeDocumentsManager::queryDocumentModel( const rtl::OUString & rDocId )
598 osl::MutexGuard aGuard( m_aMtx );
600 DocumentList::const_iterator it = m_aDocs.find( rDocId );
601 if ( it == m_aDocs.end() )
602 return uno::Reference< frame::XModel >();
604 return (*it).second.xModel;
607 //=========================================================================
608 uno::Sequence< rtl::OUString > OfficeDocumentsManager::queryDocuments()
610 osl::MutexGuard aGuard( m_aMtx );
612 uno::Sequence< rtl::OUString > aRet( m_aDocs.size() );
613 sal_Int32 nPos = 0;
615 DocumentList::const_iterator it = m_aDocs.begin();
616 while ( it != m_aDocs.end() )
618 aRet[ nPos ] = (*it).first;
619 ++it;
620 ++nPos;
622 return aRet;
625 //=========================================================================
626 rtl::OUString
627 OfficeDocumentsManager::queryStorageTitle( const rtl::OUString & rDocId )
629 osl::MutexGuard aGuard( m_aMtx );
631 DocumentList::const_iterator it = m_aDocs.find( rDocId );
632 if ( it == m_aDocs.end() )
633 return rtl::OUString();
635 return (*it).second.aTitle;
638 //=========================================================================
639 bool OfficeDocumentsManager::isDocumentPreview(
640 const uno::Reference< frame::XModel > & xModel )
642 if ( !xModel.is() )
643 return false;
645 ::comphelper::NamedValueCollection aArgs(
646 xModel->getArgs() );
647 sal_Bool bIsPreview = aArgs.getOrDefault( "Preview", sal_False );
648 return bIsPreview;
651 //=========================================================================
652 bool OfficeDocumentsManager::isHelpDocument(
653 const uno::Reference< frame::XModel > & xModel )
655 if ( !xModel.is() )
656 return false;
658 ::rtl::OUString sURL( xModel->getURL() );
659 if ( sURL.matchAsciiL( RTL_CONSTASCII_STRINGPARAM( "vnd.sun.star.help://" ) ) )
660 return true;
662 return false;
665 //=========================================================================
666 bool OfficeDocumentsManager::isWithoutOrInTopLevelFrame(
667 const uno::Reference< frame::XModel > & xModel )
669 if ( !xModel.is() )
670 return false;
672 uno::Reference< frame::XController > xController
673 = xModel->getCurrentController();
674 if ( xController.is() )
676 uno::Reference< frame::XFrame > xFrame
677 = xController->getFrame();
678 if ( xFrame.is() )
680 // don't use XFrame::isTop here. This nowadays excludes
681 // "sub documents" such as forms embedded in database documents
682 uno::Reference< awt::XTopWindow > xFrameContainer(
683 xFrame->getContainerWindow(), uno::UNO_QUERY );
684 if ( !xFrameContainer.is() )
685 return false;
689 return true;
692 //=========================================================================
693 bool OfficeDocumentsManager::isBasicIDE(
694 const uno::Reference< frame::XModel > & xModel )
696 if ( !m_xModuleMgr.is() )
698 osl::MutexGuard aGuard( m_aMtx );
699 if ( !m_xModuleMgr.is() )
703 m_xModuleMgr
704 = uno::Reference<
705 frame::XModuleManager >(
706 m_xSMgr->createInstance(
707 rtl::OUString(
708 RTL_CONSTASCII_USTRINGPARAM(
709 "com.sun.star.frame.ModuleManager" ) ) ),
710 uno::UNO_QUERY );
712 catch ( uno::Exception const & )
714 // handled below.
717 OSL_ENSURE( m_xModuleMgr .is(),
718 "Could not instanciate ModuleManager service!" );
722 if ( m_xModuleMgr.is() )
724 rtl::OUString aModule;
727 aModule = m_xModuleMgr->identify( xModel );
729 catch ( lang::IllegalArgumentException const & )
731 OSL_FAIL( "Caught IllegalArgumentException!" );
733 catch ( frame::UnknownModuleException const & )
735 OSL_FAIL( "Caught UnknownModuleException!" );
738 if ( !aModule.isEmpty() )
740 // Filter unwanted items, that are no real documents.
741 if ( aModule == "com.sun.star.script.BasicIDE" )
743 return true;
748 return false;
751 //=========================================================================
752 bool OfficeDocumentsManager::isOfficeDocument(
753 const uno::Reference< uno::XInterface > & xDoc )
755 uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
756 uno::Reference< document::XStorageBasedDocument >
757 xStorageBasedDoc( xModel, uno::UNO_QUERY );
758 if ( !xStorageBasedDoc.is() )
759 return false;
761 if ( !isWithoutOrInTopLevelFrame( xModel ) )
762 return false;
764 if ( isDocumentPreview( xModel ) )
765 return false;
767 if ( isHelpDocument( xModel ) )
768 return false;
770 if ( isBasicIDE( xModel ) )
771 return false;
773 return true;
776 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */