fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / ucb / source / ucp / tdoc / tdoc_docmgr.cxx
blob18084a7d8108c659b4fba2a8a99d330a872778e9
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 /**************************************************************************
22 TODO
23 **************************************************************************
25 *************************************************************************/
27 #include "osl/diagnose.h"
28 #include "rtl/ref.hxx"
29 #include "cppuhelper/weak.hxx"
31 #include "comphelper/documentinfo.hxx"
32 #include "comphelper/namedvaluecollection.hxx"
34 #include "com/sun/star/awt/XTopWindow.hpp"
35 #include "com/sun/star/beans/XPropertySet.hpp"
36 #include "com/sun/star/document/XDocumentEventBroadcaster.hpp"
37 #include "com/sun/star/document/XStorageBasedDocument.hpp"
38 #include "com/sun/star/frame/theGlobalEventBroadcaster.hpp"
39 #include "com/sun/star/frame/XStorable.hpp"
40 #include "com/sun/star/frame/ModuleManager.hpp"
41 #include "com/sun/star/lang/DisposedException.hpp"
42 #include "com/sun/star/util/XCloseBroadcaster.hpp"
44 #include "tdoc_docmgr.hxx"
46 using namespace com::sun::star;
47 using namespace tdoc_ucp;
49 // OfficeDocumentsCloseListener Implementation.
56 // util::XCloseListener
60 // virtual
61 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::queryClosing(
62 const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
63 throw ( util::CloseVetoException,
64 uno::RuntimeException, std::exception )
69 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::notifyClosing(
70 const lang::EventObject& Source )
71 throw ( uno::RuntimeException, std::exception )
73 if (!m_pManager) return; // disposed?
75 document::DocumentEvent aDocEvent;
76 aDocEvent.Source = Source.Source;
77 aDocEvent.EventName = "OfficeDocumentsListener::notifyClosing";
78 m_pManager->documentEventOccured( aDocEvent );
83 // lang::XDocumentEventListener (base of util::XCloseListener)
87 // virtual
88 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::disposing(
89 const lang::EventObject& /*Source*/ )
90 throw ( uno::RuntimeException, std::exception )
97 // OfficeDocumentsManager Implementation.
102 OfficeDocumentsManager::OfficeDocumentsManager(
103 const uno::Reference< uno::XComponentContext > & rxContext,
104 OfficeDocumentsEventListener * pDocEventListener )
105 : m_xContext( rxContext ),
106 m_xDocEvtNotifier( frame::theGlobalEventBroadcaster::get( rxContext ) ),
107 m_pDocEventListener( pDocEventListener ),
108 m_xDocCloseListener( new OfficeDocumentsCloseListener( this ) )
110 // Order is important (multithreaded environment)
111 uno::Reference< document::XDocumentEventBroadcaster >(
112 m_xDocEvtNotifier, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
113 buildDocumentsList();
117 // virtual
118 OfficeDocumentsManager::~OfficeDocumentsManager()
120 //OSL_ENSURE( m_aDocs.empty(), "document list not empty!" );
121 // no need to assert this: Normal shutdown of OOo could already trigger it, since the order in which
122 // objects are actually released/destroyed upon shutdown is not defined. And when we arrive *here*,
123 // OOo *is* shutting down currently, since we're held by the TDOC provider, which is disposed
124 // upon shutdown.
125 m_xDocCloseListener->Dispose();
129 void OfficeDocumentsManager::destroy()
131 uno::Reference< document::XDocumentEventBroadcaster >(
132 m_xDocEvtNotifier, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
136 static OUString
137 getDocumentId( const uno::Reference< uno::XInterface > & xDoc )
139 OUString aId;
141 // Try to get the UID directly from the document.
142 uno::Reference< beans::XPropertySet > xPropSet( xDoc, uno::UNO_QUERY );
143 if ( xPropSet.is() )
147 uno::Any aValue = xPropSet->getPropertyValue(
148 OUString( "RuntimeUID" ) );
149 aValue >>= aId;
151 catch ( beans::UnknownPropertyException const & )
153 // Not actually an error. Property is optional.
155 catch ( lang::WrappedTargetException const & )
157 OSL_FAIL( "Caught WrappedTargetException!" );
161 if ( aId.isEmpty() )
163 // fallback: generate UID from document's this pointer.
164 // normalize the interface pointer first. Else, calls with different
165 // interfaces to the same object (say, XFoo and XBar) will produce
166 // different IDs
167 uno::Reference< uno::XInterface > xNormalizedIFace( xDoc, uno::UNO_QUERY );
168 sal_Int64 nId = reinterpret_cast< sal_Int64 >( xNormalizedIFace.get() );
169 aId = OUString::number( nId );
172 OSL_ENSURE( !aId.isEmpty(), "getDocumentId - Empty id!" );
173 return aId;
178 // document::XDocumentEventListener
182 // virtual
183 void SAL_CALL OfficeDocumentsManager::documentEventOccured(
184 const document::DocumentEvent & Event )
185 throw ( uno::RuntimeException, std::exception )
188 Events documentation: OOo Developer's Guide / Writing UNO Components / Jobs
191 if ( Event.EventName == "OnLoadFinished" // document loaded
192 || Event.EventName == "OnCreate" ) // document created
194 if ( isOfficeDocument( Event.Source ) )
196 osl::MutexGuard aGuard( m_aMtx );
198 uno::Reference< frame::XModel >
199 xModel( Event.Source, uno::UNO_QUERY );
200 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
202 DocumentList::const_iterator it = m_aDocs.begin();
203 while ( it != m_aDocs.end() )
205 if ( (*it).second.xModel == xModel )
207 // already known.
208 break;
210 ++it;
213 if ( it == m_aDocs.end() )
215 // new document
217 uno::Reference< document::XStorageBasedDocument >
218 xDoc( Event.Source, uno::UNO_QUERY );
219 OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
221 uno::Reference< embed::XStorage > xStorage
222 = xDoc->getDocumentStorage();
223 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
225 rtl:: OUString aDocId = getDocumentId( Event.Source );
226 rtl:: OUString aTitle = comphelper::DocumentInfo::getDocumentTitle(
227 uno::Reference< frame::XModel >( Event.Source, uno::UNO_QUERY ) );
229 m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
231 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
232 Event.Source, uno::UNO_QUERY );
233 OSL_ENSURE( xCloseBroadcaster.is(),
234 "OnLoadFinished/OnCreate event: got no close broadcaster!" );
236 if ( xCloseBroadcaster.is() )
237 xCloseBroadcaster->addCloseListener(m_xDocCloseListener.get());
239 // Propagate document closure.
240 OSL_ENSURE( m_pDocEventListener,
241 "OnLoadFinished/OnCreate event: no owner for insert event propagation!" );
243 if ( m_pDocEventListener )
244 m_pDocEventListener->notifyDocumentOpened( aDocId );
248 else if ( Event.EventName == "OfficeDocumentsListener::notifyClosing" )
250 if ( isOfficeDocument( Event.Source ) )
252 // Document has been closed (unloaded)
254 // #163732# - Official event "OnUnload" does not work here. Event
255 // gets fired to early. Other OnUnload listeners called after this
256 // listener may still need TDOC access to the document. Remove the
257 // document from TDOC docs list on XCloseListener::notifyClosing.
258 // See OfficeDocumentsManager::OfficeDocumentsListener::notifyClosing.
260 osl::MutexGuard aGuard( m_aMtx );
262 uno::Reference< frame::XModel >
263 xModel( Event.Source, uno::UNO_QUERY );
264 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
266 DocumentList::iterator it = m_aDocs.begin();
267 while ( it != m_aDocs.end() )
269 if ( (*it).second.xModel == xModel )
271 // Propagate document closure.
272 OSL_ENSURE( m_pDocEventListener,
273 "OnUnload event: no owner for close event propagation!" );
275 if ( m_pDocEventListener )
277 OUString aDocId( (*it).first );
278 m_pDocEventListener->notifyDocumentClosed( aDocId );
280 break;
282 ++it;
285 OSL_ENSURE( it != m_aDocs.end(),
286 "OnUnload event notified for unknown document!" );
288 if ( it != m_aDocs.end() )
290 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
291 Event.Source, uno::UNO_QUERY );
292 OSL_ENSURE( xCloseBroadcaster.is(),
293 "OnUnload event: got no XCloseBroadcaster from XModel" );
295 if ( xCloseBroadcaster.is() )
296 xCloseBroadcaster->removeCloseListener(m_xDocCloseListener.get());
298 m_aDocs.erase( it );
302 else if ( Event.EventName == "OnSaveDone" )
304 if ( isOfficeDocument( Event.Source ) )
306 osl::MutexGuard aGuard( m_aMtx );
308 uno::Reference< frame::XModel >
309 xModel( Event.Source, uno::UNO_QUERY );
310 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
312 DocumentList::iterator it = m_aDocs.begin();
313 while ( it != m_aDocs.end() )
315 if ( (*it).second.xModel == xModel )
317 // Storage gets exchanged while saving.
318 uno::Reference< document::XStorageBasedDocument >
319 xDoc( Event.Source, uno::UNO_QUERY );
320 OSL_ENSURE( xDoc.is(),
321 "Got no document::XStorageBasedDocument!" );
323 uno::Reference< embed::XStorage > xStorage
324 = xDoc->getDocumentStorage();
325 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
327 (*it).second.xStorage = xStorage;
328 break;
330 ++it;
333 OSL_ENSURE( it != m_aDocs.end(),
334 "OnSaveDone event notified for unknown document!" );
337 else if ( Event.EventName == "OnSaveAsDone" )
339 if ( isOfficeDocument( Event.Source ) )
341 osl::MutexGuard aGuard( m_aMtx );
343 uno::Reference< frame::XModel >
344 xModel( Event.Source, uno::UNO_QUERY );
345 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
347 DocumentList::iterator it = m_aDocs.begin();
348 while ( it != m_aDocs.end() )
350 if ( (*it).second.xModel == xModel )
352 // Storage gets exchanged while saving.
353 uno::Reference< document::XStorageBasedDocument >
354 xDoc( Event.Source, uno::UNO_QUERY );
355 OSL_ENSURE( xDoc.is(),
356 "Got no document::XStorageBasedDocument!" );
358 uno::Reference< embed::XStorage > xStorage
359 = xDoc->getDocumentStorage();
360 OSL_ENSURE( xStorage.is(), "Got no document storage!" );
362 (*it).second.xStorage = xStorage;
364 // Adjust title.
365 (*it).second.aTitle = comphelper::DocumentInfo::getDocumentTitle( xModel );
366 break;
368 ++it;
371 OSL_ENSURE( it != m_aDocs.end(),
372 "OnSaveAsDone event notified for unknown document!" );
375 else if ( Event.EventName == "OnTitleChanged" )
377 if ( isOfficeDocument( Event.Source ) )
379 osl::MutexGuard aGuard( m_aMtx );
381 uno::Reference< frame::XModel >
382 xModel( Event.Source, uno::UNO_QUERY );
383 OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
385 DocumentList::iterator it = m_aDocs.begin();
386 while ( it != m_aDocs.end() )
388 if ( (*it).second.xModel == xModel )
390 // Adjust title.
391 rtl:: OUString aTitle = comphelper::DocumentInfo::getDocumentTitle( xModel );
392 (*it).second.aTitle = aTitle;
394 // Adjust storage.
395 uno::Reference< document::XStorageBasedDocument >
396 xDoc( Event.Source, uno::UNO_QUERY );
397 OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
399 uno::Reference< embed::XStorage > xStorage
400 = xDoc->getDocumentStorage();
401 OSL_ENSURE( xDoc.is(), "Got no document storage!" );
403 rtl:: OUString aDocId = getDocumentId( Event.Source );
405 m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
406 break;
408 ++it;
411 // OSL_ENSURE( it != m_aDocs.end(),
412 // "TitleChanged event notified for unknown document!" );
413 // TODO: re-enable this assertion. It has been disabled for now, since it breaks the assertion-free smoketest,
414 // and the fix is more difficult than what can be done now.
415 // The problem is that at the moment, when you close a SFX-based document via API, it will first
416 // fire the notifyClosing event, which will make the OfficeDocumentsManager remove the doc from its list.
417 // Then, it will notify an OnTitleChanged, then an OnUnload. Documents closed via call the notifyClosing
418 // *after* OnUnload and all other On* events.
419 // In agreement with MBA, the implementation for SfxBaseModel::Close should be changed to also send notifyClosing
420 // as last event. When this happens, the assertion here must be enabled, again.
421 // There is no bug for this, yet - IZ is currently down due to the Kenai migration.
422 // 2011-02-23 / frank.schoenheit@sun.com
429 // lang::XDocumentEventListener (base of document::XDocumentEventListener)
433 // virtual
434 void SAL_CALL OfficeDocumentsManager::disposing(
435 const lang::EventObject& /*Source*/ )
436 throw ( uno::RuntimeException, std::exception )
442 // Non-interface.
446 void OfficeDocumentsManager::buildDocumentsList()
448 uno::Reference< container::XEnumeration > xEnum
449 = m_xDocEvtNotifier->createEnumeration();
451 osl::MutexGuard aGuard( m_aMtx );
453 while ( xEnum->hasMoreElements() )
455 uno::Any aValue = xEnum->nextElement();
456 // container::NoSuchElementException
457 // lang::WrappedTargetException
461 uno::Reference< frame::XModel > xModel;
462 aValue >>= xModel;
464 if ( xModel.is() )
466 if ( isOfficeDocument( xModel ) )
468 DocumentList::const_iterator it = m_aDocs.begin();
469 while ( it != m_aDocs.end() )
471 if ( (*it).second.xModel == xModel )
473 // already known.
474 break;
476 ++it;
479 if ( it == m_aDocs.end() )
481 // new document
482 OUString aDocId = getDocumentId( xModel );
483 OUString aTitle = comphelper::DocumentInfo::getDocumentTitle( xModel );
485 uno::Reference< document::XStorageBasedDocument >
486 xDoc( xModel, uno::UNO_QUERY );
487 OSL_ENSURE( xDoc.is(),
488 "Got no document::XStorageBasedDocument!" );
490 uno::Reference< embed::XStorage > xStorage
491 = xDoc->getDocumentStorage();
492 OSL_ENSURE( xDoc.is(), "Got no document storage!" );
494 m_aDocs[ aDocId ]
495 = StorageInfo( aTitle, xStorage, xModel );
497 uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
498 xModel, uno::UNO_QUERY );
499 OSL_ENSURE( xCloseBroadcaster.is(),
500 "buildDocumentsList: got no close broadcaster!" );
502 if ( xCloseBroadcaster.is() )
503 xCloseBroadcaster->addCloseListener(m_xDocCloseListener.get());
508 catch ( lang::DisposedException const & )
510 // Note: Due to race conditions the XEnumeration can
511 // contains docs that already have been closed
517 uno::Reference< embed::XStorage >
518 OfficeDocumentsManager::queryStorage( const OUString & rDocId )
520 osl::MutexGuard aGuard( m_aMtx );
522 DocumentList::const_iterator it = m_aDocs.find( rDocId );
523 if ( it == m_aDocs.end() )
524 return uno::Reference< embed::XStorage >();
526 return (*it).second.xStorage;
530 OUString OfficeDocumentsManager::queryDocumentId(
531 const uno::Reference< frame::XModel > & xModel )
533 return getDocumentId( xModel );
537 uno::Reference< frame::XModel >
538 OfficeDocumentsManager::queryDocumentModel( const OUString & rDocId )
540 osl::MutexGuard aGuard( m_aMtx );
542 DocumentList::const_iterator it = m_aDocs.find( rDocId );
543 if ( it == m_aDocs.end() )
544 return uno::Reference< frame::XModel >();
546 return (*it).second.xModel;
550 uno::Sequence< OUString > OfficeDocumentsManager::queryDocuments()
552 osl::MutexGuard aGuard( m_aMtx );
554 uno::Sequence< OUString > aRet( m_aDocs.size() );
555 sal_Int32 nPos = 0;
557 DocumentList::const_iterator it = m_aDocs.begin();
558 while ( it != m_aDocs.end() )
560 aRet[ nPos ] = (*it).first;
561 ++it;
562 ++nPos;
564 return aRet;
568 OUString
569 OfficeDocumentsManager::queryStorageTitle( const OUString & rDocId )
571 osl::MutexGuard aGuard( m_aMtx );
573 DocumentList::const_iterator it = m_aDocs.find( rDocId );
574 if ( it == m_aDocs.end() )
575 return OUString();
577 return (*it).second.aTitle;
581 bool OfficeDocumentsManager::isDocumentPreview(
582 const uno::Reference< frame::XModel > & xModel )
584 if ( !xModel.is() )
585 return false;
587 ::comphelper::NamedValueCollection aArgs(
588 xModel->getArgs() );
589 bool bIsPreview = aArgs.getOrDefault( "Preview", sal_False );
590 return bIsPreview;
594 bool OfficeDocumentsManager::isHelpDocument(
595 const uno::Reference< frame::XModel > & xModel )
597 if ( !xModel.is() )
598 return false;
600 OUString sURL( xModel->getURL() );
601 if ( sURL.match( "vnd.sun.star.help://" ) )
602 return true;
604 return false;
608 bool OfficeDocumentsManager::isWithoutOrInTopLevelFrame(
609 const uno::Reference< frame::XModel > & xModel )
611 if ( !xModel.is() )
612 return false;
614 uno::Reference< frame::XController > xController
615 = xModel->getCurrentController();
616 if ( xController.is() )
618 uno::Reference< frame::XFrame > xFrame
619 = xController->getFrame();
620 if ( xFrame.is() )
622 // don't use XFrame::isTop here. This nowadays excludes
623 // "sub documents" such as forms embedded in database documents
624 uno::Reference< awt::XTopWindow > xFrameContainer(
625 xFrame->getContainerWindow(), uno::UNO_QUERY );
626 if ( !xFrameContainer.is() )
627 return false;
631 return true;
635 bool OfficeDocumentsManager::isBasicIDE(
636 const uno::Reference< frame::XModel > & xModel )
638 if ( !m_xModuleMgr.is() )
640 osl::MutexGuard aGuard( m_aMtx );
641 if ( !m_xModuleMgr.is() )
645 m_xModuleMgr = frame::ModuleManager::create( m_xContext );
647 catch ( uno::Exception const & )
649 // handled below.
652 OSL_ENSURE( m_xModuleMgr .is(),
653 "Could not instanciate ModuleManager service!" );
657 if ( m_xModuleMgr.is() )
659 OUString aModule;
662 aModule = m_xModuleMgr->identify( xModel );
664 catch ( lang::IllegalArgumentException const & )
666 OSL_FAIL( "Caught IllegalArgumentException!" );
668 catch ( frame::UnknownModuleException const & )
670 OSL_FAIL( "Caught UnknownModuleException!" );
673 if ( !aModule.isEmpty() )
675 // Filter unwanted items, that are no real documents.
676 if ( aModule == "com.sun.star.script.BasicIDE" )
678 return true;
683 return false;
687 bool OfficeDocumentsManager::isOfficeDocument(
688 const uno::Reference< uno::XInterface > & xDoc )
690 uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
691 uno::Reference< document::XStorageBasedDocument >
692 xStorageBasedDoc( xModel, uno::UNO_QUERY );
693 if ( !xStorageBasedDoc.is() )
694 return false;
696 if ( !isWithoutOrInTopLevelFrame( xModel ) )
697 return false;
699 if ( isDocumentPreview( xModel ) )
700 return false;
702 if ( isHelpDocument( xModel ) )
703 return false;
705 if ( isBasicIDE( xModel ) )
706 return false;
708 return true;
711 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */