LibreOffice Module ucb (master)  1
tdoc_docmgr.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 
21 #include <osl/diagnose.h>
22 #include <rtl/ref.hxx>
23 
26 #include <comphelper/sequence.hxx>
27 
28 #include <com/sun/star/awt/XTopWindow.hpp>
29 #include <com/sun/star/beans/XPropertySet.hpp>
30 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
31 #include <com/sun/star/document/XStorageBasedDocument.hpp>
32 #include <com/sun/star/frame/UnknownModuleException.hpp>
33 #include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
34 #include <com/sun/star/frame/ModuleManager.hpp>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include <com/sun/star/lang/NotInitializedException.hpp>
37 #include <com/sun/star/util/XCloseBroadcaster.hpp>
38 
39 #include "tdoc_docmgr.hxx"
40 #include "tdoc_provider.hxx"
41 
42 using namespace com::sun::star;
43 using namespace tdoc_ucp;
44 
45 // OfficeDocumentsCloseListener Implementation.
46 
47 
48 // util::XCloseListener
49 
50 
51 // virtual
52 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::queryClosing(
53  const lang::EventObject& /*Source*/, sal_Bool /*GetsOwnership*/ )
54 {
55 }
56 
57 
58 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::notifyClosing(
59  const lang::EventObject& Source )
60 {
61  if (!m_pManager) return; // disposed?
62 
63  document::DocumentEvent aDocEvent;
64  aDocEvent.Source = Source.Source;
65  aDocEvent.EventName = "OfficeDocumentsListener::notifyClosing";
66  m_pManager->documentEventOccured( aDocEvent );
67 }
68 
69 
70 // lang::XDocumentEventListener (base of util::XCloseListener)
71 
72 
73 // virtual
74 void SAL_CALL OfficeDocumentsManager::OfficeDocumentsCloseListener::disposing(
75  const lang::EventObject& /*Source*/ )
76 {
77 }
78 
79 
80 // OfficeDocumentsManager Implementation.
81 
82 
83 OfficeDocumentsManager::OfficeDocumentsManager(
84  const uno::Reference< uno::XComponentContext > & rxContext,
85  ContentProvider * pDocEventListener )
86 : m_xContext( rxContext ),
87  m_xDocEvtNotifier( frame::theGlobalEventBroadcaster::get( rxContext ) ),
88  m_pDocEventListener( pDocEventListener ),
89  m_xDocCloseListener( new OfficeDocumentsCloseListener( this ) )
90 {
91  // Order is important (multithreaded environment)
92  uno::Reference< document::XDocumentEventBroadcaster >(
93  m_xDocEvtNotifier, uno::UNO_QUERY_THROW )->addDocumentEventListener( this );
95 }
96 
97 
98 // virtual
100 {
101  //OSL_ENSURE( m_aDocs.empty(), "document list not empty!" );
102  // no need to assert this: Normal shutdown of LibreOffice could already trigger it, since the order
103  // in which objects are actually released/destroyed upon shutdown is not defined. And when we
104  // arrive *here*, LibreOffice *is* shutting down currently, since we're held by the TDOC provider,
105  // which is disposed upon shutdown.
106  m_xDocCloseListener->Dispose();
107 }
108 
109 
111 {
112  uno::Reference< document::XDocumentEventBroadcaster >(
113  m_xDocEvtNotifier, uno::UNO_QUERY_THROW )->removeDocumentEventListener( this );
114 }
115 
116 
117 static OUString
118 getDocumentId( const uno::Reference< uno::XInterface > & xDoc )
119 {
120  OUString aId;
121 
122  // Try to get the UID directly from the document.
123  uno::Reference< beans::XPropertySet > xPropSet( xDoc, uno::UNO_QUERY );
124  if ( xPropSet.is() )
125  {
126  try
127  {
128  uno::Any aValue = xPropSet->getPropertyValue("RuntimeUID");
129  aValue >>= aId;
130  }
131  catch ( beans::UnknownPropertyException const & )
132  {
133  // Not actually an error. Property is optional.
134  }
135  catch ( lang::WrappedTargetException const & )
136  {
137  OSL_FAIL( "Caught WrappedTargetException!" );
138  }
139  }
140 
141  if ( aId.isEmpty() )
142  {
143  // fallback: generate UID from document's this pointer.
144  // normalize the interface pointer first. Else, calls with different
145  // interfaces to the same object (say, XFoo and XBar) will produce
146  // different IDs
147  uno::Reference< uno::XInterface > xNormalizedIFace( xDoc, uno::UNO_QUERY );
148  sal_Int64 nId = reinterpret_cast< sal_Int64 >( xNormalizedIFace.get() );
149  aId = OUString::number( nId );
150  }
151 
152  OSL_ENSURE( !aId.isEmpty(), "getDocumentId - Empty id!" );
153  return aId;
154 }
155 
156 
157 // document::XDocumentEventListener
158 
159 
160 // virtual
162  const document::DocumentEvent & Event )
163 {
164 /*
165  Events documentation: OOo Developer's Guide / Writing UNO Components /
166  Integrating Components into OpenOffice.org / Jobs
167 */
168 
169  if ( Event.EventName == "OnLoadFinished" // document loaded
170  || Event.EventName == "OnCreate" ) // document created
171  {
172  if ( isOfficeDocument( Event.Source ) )
173  {
174  uno::Reference<frame::XModel> const xModel(
175  Event.Source, uno::UNO_QUERY );
176  OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
177 
178  bool found(false);
179 
180  {
181  osl::MutexGuard aGuard( m_aMtx );
182 
183  found = std::any_of(m_aDocs.begin(), m_aDocs.end(),
184  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
185  }
186 
187  if (!found)
188  {
189  // no mutex to avoid deadlocks!
190  // need no lock to access const members, ContentProvider is safe
191 
192  // new document
193 
194  uno::Reference< document::XStorageBasedDocument >
195  xDoc( Event.Source, uno::UNO_QUERY );
196  OSL_ENSURE( xDoc.is(), "Got no document::XStorageBasedDocument!" );
197 
198  uno::Reference< embed::XStorage > xStorage
199  = xDoc->getDocumentStorage();
200  OSL_ENSURE( xStorage.is(), "Got no document storage!" );
201 
202  rtl:: OUString aDocId = getDocumentId( Event.Source );
203  rtl:: OUString aTitle = comphelper::DocumentInfo::getDocumentTitle(
204  uno::Reference< frame::XModel >( Event.Source, uno::UNO_QUERY ) );
205 
206  {
207  osl::MutexGuard g(m_aMtx);
208  m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
209  }
210 
211  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
212  Event.Source, uno::UNO_QUERY );
213  OSL_ENSURE( xCloseBroadcaster.is(),
214  "OnLoadFinished/OnCreate event: got no close broadcaster!" );
215 
216  if ( xCloseBroadcaster.is() )
217  xCloseBroadcaster->addCloseListener(m_xDocCloseListener.get());
218 
219  // Propagate document closure.
220  OSL_ENSURE( m_pDocEventListener,
221  "OnLoadFinished/OnCreate event: no owner for insert event propagation!" );
222 
223  if ( m_pDocEventListener )
225  }
226  }
227  }
228  else if ( Event.EventName == "OfficeDocumentsListener::notifyClosing" )
229  {
230  if ( isOfficeDocument( Event.Source ) )
231  {
232  // Document has been closed (unloaded)
233 
234  // Official event "OnUnload" does not work here. Event
235  // gets fired too early. Other OnUnload listeners called after this
236  // listener may still need TDOC access to the document. Remove the
237  // document from TDOC docs list on XCloseListener::notifyClosing.
238  // See OfficeDocumentsManager::OfficeDocumentsListener::notifyClosing.
239 
240  uno::Reference< frame::XModel >
241  xModel( Event.Source, uno::UNO_QUERY );
242  OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
243 
244  bool found(false);
245  OUString aDocId;
246 
247  {
248  osl::MutexGuard aGuard( m_aMtx );
249 
250  auto it = std::find_if(m_aDocs.begin(), m_aDocs.end(),
251  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
252  if ( it != m_aDocs.end() )
253  {
254  aDocId = (*it).first;
255  found = true;
256  m_aDocs.erase( it );
257  }
258  }
259 
260  OSL_ENSURE( found,
261  "OnUnload event notified for unknown document!" );
262 
263  if (found)
264  {
265  // Propagate document closure.
266  OSL_ENSURE( m_pDocEventListener,
267  "OnUnload event: no owner for close event propagation!" );
269  {
271  }
272  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
273  Event.Source, uno::UNO_QUERY );
274  OSL_ENSURE( xCloseBroadcaster.is(),
275  "OnUnload event: got no XCloseBroadcaster from XModel" );
276  if ( xCloseBroadcaster.is() )
277  xCloseBroadcaster->removeCloseListener(m_xDocCloseListener.get());
278  }
279  }
280  }
281  else if ( Event.EventName == "OnSaveDone" )
282  {
283  if ( isOfficeDocument( Event.Source ) )
284  {
285  // Storage gets exchanged while saving.
286  uno::Reference<document::XStorageBasedDocument> const xDoc(
287  Event.Source, uno::UNO_QUERY );
288  OSL_ENSURE( xDoc.is(),
289  "Got no document::XStorageBasedDocument!" );
290  uno::Reference<embed::XStorage> const xStorage(
291  xDoc->getDocumentStorage());
292  OSL_ENSURE( xStorage.is(), "Got no document storage!" );
293 
294  uno::Reference< frame::XModel >
295  xModel( Event.Source, uno::UNO_QUERY );
296  OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
297 
298  osl::MutexGuard aGuard( m_aMtx );
299 
300  DocumentList::iterator it = std::find_if(m_aDocs.begin(), m_aDocs.end(),
301  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
302 
303  OSL_ENSURE( it != m_aDocs.end(),
304  "OnSaveDone event notified for unknown document!" );
305  if ( it != m_aDocs.end() )
306  {
307  (*it).second.xStorage = xStorage;
308  }
309  }
310  }
311  else if ( Event.EventName == "OnSaveAsDone" )
312  {
313  if ( isOfficeDocument( Event.Source ) )
314  {
315  // Storage gets exchanged while saving.
316  uno::Reference<document::XStorageBasedDocument> const xDoc(
317  Event.Source, uno::UNO_QUERY );
318  OSL_ENSURE( xDoc.is(),
319  "Got no document::XStorageBasedDocument!" );
320  uno::Reference<embed::XStorage> const xStorage(
321  xDoc->getDocumentStorage());
322  OSL_ENSURE( xStorage.is(), "Got no document storage!" );
323 
324  uno::Reference< frame::XModel >
325  xModel( Event.Source, uno::UNO_QUERY );
326  OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
327 
328  OUString const title(comphelper::DocumentInfo::getDocumentTitle(xModel));
329 
330  osl::MutexGuard aGuard( m_aMtx );
331 
332  DocumentList::iterator it = std::find_if(m_aDocs.begin(), m_aDocs.end(),
333  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
334 
335  OSL_ENSURE( it != m_aDocs.end(),
336  "OnSaveAsDone event notified for unknown document!" );
337  if ( it != m_aDocs.end() )
338  {
339  (*it).second.xStorage = xStorage;
340 
341  // Adjust title.
342  (*it).second.aTitle = title;
343  }
344  }
345  }
346  else if ( Event.EventName == "OnTitleChanged"
347  || Event.EventName == "OnStorageChanged" )
348  {
349  if ( isOfficeDocument( Event.Source ) )
350  {
351  // Storage gets exchanged while saving.
352  uno::Reference<document::XStorageBasedDocument> const xDoc(
353  Event.Source, uno::UNO_QUERY );
354  OSL_ENSURE( xDoc.is(),
355  "Got no document::XStorageBasedDocument!" );
356  uno::Reference<embed::XStorage> const xStorage(
357  xDoc->getDocumentStorage());
358  OSL_ENSURE( xStorage.is(), "Got no document storage!" );
359 
360  uno::Reference< frame::XModel >
361  xModel( Event.Source, uno::UNO_QUERY );
362  OSL_ENSURE( xModel.is(), "Got no frame::XModel!" );
363 
364  OUString const aTitle(comphelper::DocumentInfo::getDocumentTitle(xModel));
365 
366  OUString const aDocId(getDocumentId(Event.Source));
367 
368  osl::MutexGuard aGuard( m_aMtx );
369 
370  DocumentList::iterator it = std::find_if(m_aDocs.begin(), m_aDocs.end(),
371  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
372  if ( it != m_aDocs.end() )
373  {
374  // Adjust title.
375  (*it).second.aTitle = aTitle;
376 
377  m_aDocs[ aDocId ] = StorageInfo( aTitle, xStorage, xModel );
378  }
379 
380 // OSL_ENSURE( it != m_aDocs.end(),
381 // "TitleChanged event notified for unknown document!" );
382  // TODO: re-enable this assertion. It has been disabled for now, since it breaks the assertion-free smoketest,
383  // and the fix is more difficult than what can be done now.
384  // The problem is that at the moment, when you close a SFX-based document via API, it will first
385  // fire the notifyClosing event, which will make the OfficeDocumentsManager remove the doc from its list.
386  // Then, it will notify an OnTitleChanged, then an OnUnload. Documents closed via call the notifyClosing
387  // *after* OnUnload and all other On* events.
388  // In agreement with MBA, the implementation for SfxBaseModel::Close should be changed to also send notifyClosing
389  // as last event. When this happens, the assertion here must be enabled, again.
390  }
391  }
392 }
393 
394 // lang::XDocumentEventListener (base of document::XDocumentEventListener)
395 
396 // virtual
398  const lang::EventObject& /*Source*/ )
399 {
400 }
401 
402 // Non-interface.
403 
405 {
406  uno::Reference< container::XEnumeration > xEnum
407  = m_xDocEvtNotifier->createEnumeration();
408 
409  while ( xEnum->hasMoreElements() )
410  {
411  uno::Any aValue = xEnum->nextElement();
412  // container::NoSuchElementException
413  // lang::WrappedTargetException
414 
415  try
416  {
417  uno::Reference< frame::XModel > xModel;
418  aValue >>= xModel;
419 
420  if ( xModel.is() )
421  {
422  if ( isOfficeDocument( xModel ) )
423  {
424  bool found(false);
425 
426  {
427  osl::MutexGuard aGuard( m_aMtx );
428 
429  found = std::any_of(m_aDocs.begin(), m_aDocs.end(),
430  [&xModel](const DocumentList::value_type& rEntry) { return rEntry.second.xModel == xModel; });
431  }
432 
433  if (!found)
434  {
435  // new document
436  OUString aDocId = getDocumentId( xModel );
437  OUString aTitle = comphelper::DocumentInfo::getDocumentTitle( xModel );
438 
439  uno::Reference< document::XStorageBasedDocument >
440  xDoc( xModel, uno::UNO_QUERY );
441  OSL_ENSURE( xDoc.is(),
442  "Got no document::XStorageBasedDocument!" );
443 
444  uno::Reference< embed::XStorage > xStorage
445  = xDoc->getDocumentStorage();
446  OSL_ENSURE( xStorage.is(), "Got no document storage!" );
447 
448  {
449  osl::MutexGuard aGuard( m_aMtx );
450  m_aDocs[ aDocId ]
451  = StorageInfo( aTitle, xStorage, xModel );
452  }
453 
454  uno::Reference< util::XCloseBroadcaster > xCloseBroadcaster(
455  xModel, uno::UNO_QUERY );
456  OSL_ENSURE( xCloseBroadcaster.is(),
457  "buildDocumentsList: got no close broadcaster!" );
458 
459  if ( xCloseBroadcaster.is() )
460  xCloseBroadcaster->addCloseListener(m_xDocCloseListener.get());
461  }
462  }
463  }
464  }
465  catch ( lang::DisposedException const & )
466  {
467  // Note: Due to race conditions the XEnumeration can
468  // contain docs that have already been closed
469  }
470  catch ( lang::NotInitializedException const & )
471  {
472  // Note: Due to race conditions the XEnumeration can
473  // contain docs that are still uninitialized
474  }
475  }
476 }
477 
478 uno::Reference< embed::XStorage >
479 OfficeDocumentsManager::queryStorage( const OUString & rDocId )
480 {
481  osl::MutexGuard aGuard( m_aMtx );
482 
483  DocumentList::const_iterator it = m_aDocs.find( rDocId );
484  if ( it == m_aDocs.end() )
485  return uno::Reference< embed::XStorage >();
486 
487  return (*it).second.xStorage;
488 }
489 
490 
492  const uno::Reference< frame::XModel > & xModel )
493 {
494  return getDocumentId( xModel );
495 }
496 
497 
498 uno::Reference< frame::XModel >
500 {
501  osl::MutexGuard aGuard( m_aMtx );
502 
503  DocumentList::const_iterator it = m_aDocs.find( rDocId );
504  if ( it == m_aDocs.end() )
505  return uno::Reference< frame::XModel >();
506 
507  return (*it).second.xModel;
508 }
509 
510 
511 uno::Sequence< OUString > OfficeDocumentsManager::queryDocuments()
512 {
513  osl::MutexGuard aGuard( m_aMtx );
514 
516 }
517 
518 
519 OUString
521 {
522  osl::MutexGuard aGuard( m_aMtx );
523 
524  DocumentList::const_iterator it = m_aDocs.find( rDocId );
525  if ( it == m_aDocs.end() )
526  return OUString();
527 
528  return (*it).second.aTitle;
529 }
530 
531 
533  const uno::Reference< frame::XModel > & xModel )
534 {
535  if ( !xModel.is() )
536  return false;
537 
539  xModel->getArgs() );
540  bool bIsPreview = aArgs.getOrDefault( "Preview", false );
541  return bIsPreview;
542 }
543 
544 
546  const uno::Reference< frame::XModel > & xModel )
547 {
548  if ( !xModel.is() )
549  return false;
550 
551  OUString sURL( xModel->getURL() );
552  return sURL.match( "vnd.sun.star.help://" );
553 }
554 
555 
557  const uno::Reference< frame::XModel > & xModel )
558 {
559  if ( !xModel.is() )
560  return false;
561 
562  uno::Reference< frame::XController > xController
563  = xModel->getCurrentController();
564  if ( xController.is() )
565  {
566  uno::Reference< frame::XFrame > xFrame
567  = xController->getFrame();
568  if ( xFrame.is() )
569  {
570  // don't use XFrame::isTop here. This nowadays excludes
571  // "sub documents" such as forms embedded in database documents
572  uno::Reference< awt::XTopWindow > xFrameContainer(
573  xFrame->getContainerWindow(), uno::UNO_QUERY );
574  if ( !xFrameContainer.is() )
575  return false;
576  }
577  }
578 
579  return true;
580 }
581 
582 
584  const uno::Reference< frame::XModel > & xModel )
585 {
586  if ( !m_xModuleMgr.is() )
587  {
588  osl::MutexGuard aGuard( m_aMtx );
589  if ( !m_xModuleMgr.is() )
590  {
591  try
592  {
593  m_xModuleMgr = frame::ModuleManager::create( m_xContext );
594  }
595  catch ( uno::Exception const & )
596  {
597  // handled below.
598  }
599 
600  OSL_ENSURE( m_xModuleMgr .is(),
601  "Could not instantiate ModuleManager service!" );
602  }
603  }
604 
605  if ( m_xModuleMgr.is() )
606  {
607  OUString aModule;
608  try
609  {
610  aModule = m_xModuleMgr->identify( xModel );
611  }
612  catch ( lang::IllegalArgumentException const & )
613  {
614  OSL_FAIL( "Caught IllegalArgumentException!" );
615  }
616  catch ( frame::UnknownModuleException const & )
617  {
618  OSL_FAIL( "Caught UnknownModuleException!" );
619  }
620 
621  if ( !aModule.isEmpty() )
622  {
623  // Filter unwanted items, that are no real documents.
624  if ( aModule == "com.sun.star.script.BasicIDE" )
625  {
626  return true;
627  }
628  }
629  }
630 
631  return false;
632 }
633 
634 
636  const uno::Reference< uno::XInterface > & xDoc )
637 {
638  uno::Reference< frame::XModel > xModel( xDoc, uno::UNO_QUERY );
639  uno::Reference< document::XStorageBasedDocument >
640  xStorageBasedDoc( xModel, uno::UNO_QUERY );
641  if ( !xStorageBasedDoc.is() )
642  return false;
643 
644  if ( !isWithoutOrInTopLevelFrame( xModel ) )
645  return false;
646 
647  if ( isDocumentPreview( xModel ) )
648  return false;
649 
650  if ( isHelpDocument( xModel ) )
651  return false;
652 
653  if ( isBasicIDE( xModel ) )
654  return false;
655 
656  return true;
657 }
658 
659 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
css::uno::Reference< css::linguistic2::XProofreadingIterator > get(css::uno::Reference< css::uno::XComponentContext > const &context)
css::uno::Reference< css::uno::XComponentContext > m_xContext
::rtl::Reference< OfficeDocumentsCloseListener > const m_xDocCloseListener
static bool isDocumentPreview(const css::uno::Reference< css::frame::XModel > &xModel)
Reference< XFrame > xFrame
sal_Int16 nId
css::uno::Reference< css::embed::XStorage > queryStorage(const OUString &rDocId)
Reference< XController > xController
static bool isWithoutOrInTopLevelFrame(const css::uno::Reference< css::frame::XModel > &xModel)
css::uno::Reference< css::frame::XGlobalEventBroadcaster > m_xDocEvtNotifier
css::uno::Sequence< OUString > queryDocuments()
ContentProvider *const m_pDocEventListener
css::uno::Reference< css::frame::XModel > queryDocumentModel(const OUString &rDocId)
unsigned char sal_Bool
bool isBasicIDE(const css::uno::Reference< css::frame::XModel > &xModel)
COMPHELPER_DLLPUBLIC OUString getDocumentTitle(const css::uno::Reference< css::frame::XModel > &_rxDocument)
static OUString queryDocumentId(const css::uno::Reference< css::frame::XModel > &xModel)
css::uno::Reference< css::frame::XModuleManager2 > m_xModuleMgr
bool isOfficeDocument(const css::uno::Reference< css::uno::XInterface > &xDoc)
static bool isHelpDocument(const css::uno::Reference< css::frame::XModel > &xModel)
virtual void SAL_CALL disposing(const css::lang::EventObject &Source) override
VALUE_TYPE getOrDefault(const sal_Char *_pAsciiValueName, const VALUE_TYPE &_rDefault) const
virtual ~OfficeDocumentsManager() override
Definition: tdoc_docmgr.cxx:99
void notifyDocumentClosed(const OUString &rDocId)
virtual void SAL_CALL documentEventOccured(const css::document::DocumentEvent &Event) override
void notifyDocumentOpened(const OUString &rDocId)
Reference< XModel > xModel
static OUString getDocumentId(const uno::Reference< uno::XInterface > &xDoc)
OUString queryStorageTitle(const OUString &rDocId)
css::uno::Sequence< typename M::key_type > mapKeysToSequence(M const &map)
const uno::Reference< uno::XComponentContext > m_xContext