fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / framework / source / fwe / helper / titlehelper.cxx
blobd8c44d37b74bf3688dc6990ecd635e0480c033e7
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 .
20 #include <framework/titlehelper.hxx>
21 #include <services.h>
22 #include <properties.h>
24 #include <com/sun/star/frame/UntitledNumbersConst.hpp>
25 #include <com/sun/star/frame/XStorable.hpp>
26 #include <com/sun/star/frame/ModuleManager.hpp>
27 #include <com/sun/star/container/XNameAccess.hpp>
28 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
29 #include <com/sun/star/beans/XMaterialHolder.hpp>
31 #include <unotools/configmgr.hxx>
32 #include <unotools/bootstrap.hxx>
33 #include <comphelper/sequenceashashmap.hxx>
34 #include <rtl/ustrbuf.hxx>
35 #include <osl/mutex.hxx>
36 #include <tools/urlobj.hxx>
38 namespace framework{
40 TitleHelper::TitleHelper(const css::uno::Reference< css::uno::XComponentContext >& rxContext)
41 : ::cppu::BaseMutex ()
42 , m_xContext (rxContext)
43 , m_xOwner ()
44 , m_xUntitledNumbers()
45 , m_xSubTitle ()
46 , m_bExternalTitle (false)
47 , m_sTitle ()
48 , m_nLeasedNumber (css::frame::UntitledNumbersConst::INVALID_NUMBER)
49 , m_aListener (m_aMutex)
53 TitleHelper::~TitleHelper()
57 void TitleHelper::setOwner(const css::uno::Reference< css::uno::XInterface >& xOwner)
59 // SYNCHRONIZED ->
60 ::osl::ResettableMutexGuard aLock(m_aMutex);
62 m_xOwner = xOwner;
64 aLock.clear ();
65 // <- SYNCHRONIZED
67 css::uno::Reference< css::frame::XModel > xModel(xOwner, css::uno::UNO_QUERY);
68 if (xModel.is ())
70 impl_startListeningForModel (xModel);
71 return;
74 css::uno::Reference< css::frame::XController > xController(xOwner, css::uno::UNO_QUERY);
75 if (xController.is ())
77 impl_startListeningForController (xController);
78 return;
81 css::uno::Reference< css::frame::XFrame > xFrame(xOwner, css::uno::UNO_QUERY);
82 if (xFrame.is ())
84 impl_startListeningForFrame (xFrame);
85 return;
89 OUString SAL_CALL TitleHelper::getTitle()
90 throw (css::uno::RuntimeException, std::exception)
92 // SYNCHRONIZED ->
93 ::osl::ResettableMutexGuard aLock(m_aMutex);
95 // An external title will win always and disable all internal logic about
96 // creating/using a title value.
97 // Even an empty string will be accepted as valid title !
98 if (m_bExternalTitle)
99 return m_sTitle;
101 // Title seems to be up-to-date. Return it directly.
102 if (!m_sTitle.isEmpty())
103 return m_sTitle;
105 // Title seems to be unused till now ... do bootstraping
106 impl_updateTitle (true);
108 return m_sTitle;
110 // <- SYNCHRONIZED
113 void TitleHelper::connectWithUntitledNumbers (const css::uno::Reference< css::frame::XUntitledNumbers >& xNumbers)
115 // SYNCHRONIZED ->
116 ::osl::ResettableMutexGuard aLock(m_aMutex);
118 m_xUntitledNumbers = xNumbers;
120 // <- SYNCHRONIZED
123 void SAL_CALL TitleHelper::setTitle(const OUString& sTitle)
124 throw (css::uno::RuntimeException, std::exception)
126 // SYNCHRONIZED ->
127 ::osl::ResettableMutexGuard aLock(m_aMutex);
129 m_bExternalTitle = true;
130 m_sTitle = sTitle;
132 aLock.clear ();
133 // <- SYNCHRONIZED
135 impl_sendTitleChangedEvent ();
138 void SAL_CALL TitleHelper::addTitleChangeListener(const css::uno::Reference< css::frame::XTitleChangeListener >& xListener)
139 throw (css::uno::RuntimeException, std::exception)
141 // container is threadsafe by himself
142 m_aListener.addInterface( cppu::UnoType<css::frame::XTitleChangeListener>::get(), xListener );
145 void SAL_CALL TitleHelper::removeTitleChangeListener(const css::uno::Reference< css::frame::XTitleChangeListener >& xListener)
146 throw (css::uno::RuntimeException, std::exception)
148 // container is threadsafe by himself
149 m_aListener.removeInterface( cppu::UnoType<css::frame::XTitleChangeListener>::get(), xListener );
152 void SAL_CALL TitleHelper::titleChanged(const css::frame::TitleChangedEvent& aEvent)
153 throw (css::uno::RuntimeException, std::exception)
155 // SYNCHRONIZED ->
156 ::osl::ResettableMutexGuard aLock(m_aMutex);
158 css::uno::Reference< css::frame::XTitle > xSubTitle(m_xSubTitle.get (), css::uno::UNO_QUERY);
160 aLock.clear ();
161 // <- SYNCHRONIZED
163 if (aEvent.Source != xSubTitle)
164 return;
166 impl_updateTitle ();
169 void SAL_CALL TitleHelper::documentEventOccured(const css::document::DocumentEvent& aEvent)
170 throw (css::uno::RuntimeException, std::exception)
172 if ( ! aEvent.EventName.equalsIgnoreAsciiCase("OnSaveAsDone")
173 && ! aEvent.EventName.equalsIgnoreAsciiCase("OnModeChanged")
174 && ! aEvent.EventName.equalsIgnoreAsciiCase("OnTitleChanged"))
175 return;
177 // SYNCHRONIZED ->
178 ::osl::ResettableMutexGuard aLock(m_aMutex);
180 css::uno::Reference< css::frame::XModel > xOwner(m_xOwner.get (), css::uno::UNO_QUERY);
182 aLock.clear ();
183 // <- SYNCHRONIZED
185 if (aEvent.Source != xOwner
186 || ((aEvent.EventName.equalsIgnoreAsciiCase("OnModeChanged")
187 || aEvent.EventName.equalsIgnoreAsciiCase("OnTitleChanged"))
188 && !xOwner.is()))
190 return;
193 impl_updateTitle ();
196 void SAL_CALL TitleHelper::frameAction(const css::frame::FrameActionEvent& aEvent)
197 throw(css::uno::RuntimeException, std::exception)
199 // SYNCHRONIZED ->
200 ::osl::ResettableMutexGuard aLock(m_aMutex);
202 css::uno::Reference< css::frame::XFrame > xOwner(m_xOwner.get (), css::uno::UNO_QUERY);
204 aLock.clear ();
205 // <- SYNCHRONIZED
207 if (aEvent.Source != xOwner)
208 return;
210 // we are interested on events only, which must trigger a title bar update
211 // because component was changed.
212 if (
213 (aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED ) ||
214 (aEvent.Action == css::frame::FrameAction_COMPONENT_REATTACHED) ||
215 (aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING )
218 impl_updateListeningForFrame (xOwner);
219 impl_updateTitle ();
223 void SAL_CALL TitleHelper::disposing(const css::lang::EventObject& aEvent)
224 throw (css::uno::RuntimeException, std::exception)
226 // SYNCHRONIZED ->
227 ::osl::ResettableMutexGuard aLock(m_aMutex);
228 css::uno::Reference< css::uno::XInterface > xOwner (m_xOwner.get() , css::uno::UNO_QUERY);
229 css::uno::Reference< css::frame::XUntitledNumbers > xNumbers (m_xUntitledNumbers.get(), css::uno::UNO_QUERY);
230 ::sal_Int32 nLeasedNumber = m_nLeasedNumber;
231 aLock.clear ();
232 // <- SYNCHRONIZED
234 if ( ! xOwner.is ())
235 return;
237 if (xOwner != aEvent.Source)
238 return;
240 if (
241 (xNumbers.is () ) &&
242 (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
244 xNumbers->releaseNumber (nLeasedNumber);
246 // SYNCHRONIZED ->
247 aLock.reset ();
249 m_sTitle = OUString ();
250 m_nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
252 aLock.clear ();
253 // <- SYNCHRONIZED
255 impl_sendTitleChangedEvent ();
258 void TitleHelper::impl_sendTitleChangedEvent ()
260 // SYNCHRONIZED ->
261 ::osl::ResettableMutexGuard aLock(m_aMutex);
263 css::frame::TitleChangedEvent aEvent(m_xOwner.get (), m_sTitle);
265 aLock.clear ();
266 // <- SYNCHRONIZED
268 ::cppu::OInterfaceContainerHelper* pContainer = m_aListener.getContainer( cppu::UnoType<css::frame::XTitleChangeListener>::get());
269 if ( ! pContainer)
270 return;
272 ::cppu::OInterfaceIteratorHelper pIt( *pContainer );
273 while ( pIt.hasMoreElements() )
277 static_cast<css::frame::XTitleChangeListener*>(pIt.next())->titleChanged( aEvent );
279 catch(const css::uno::Exception&)
281 pIt.remove();
286 void TitleHelper::impl_updateTitle (bool init)
288 // SYNCHRONIZED ->
289 ::osl::ResettableMutexGuard aLock(m_aMutex);
291 css::uno::Reference< css::frame::XModel > xModel (m_xOwner.get(), css::uno::UNO_QUERY);
292 css::uno::Reference< css::frame::XController > xController(m_xOwner.get(), css::uno::UNO_QUERY);
293 css::uno::Reference< css::frame::XFrame > xFrame (m_xOwner.get(), css::uno::UNO_QUERY);
295 aLock.clear ();
296 // <- SYNCHRONIZED
298 if (xModel.is ())
300 impl_updateTitleForModel (xModel, init);
302 else if (xController.is ())
304 impl_updateTitleForController (xController, init);
306 else if (xFrame.is ())
308 impl_updateTitleForFrame (xFrame, init);
312 void TitleHelper::impl_updateTitleForModel (const css::uno::Reference< css::frame::XModel >& xModel, bool init)
314 // SYNCHRONIZED ->
315 ::osl::ResettableMutexGuard aLock(m_aMutex);
317 // external title wont be updated internally !
318 // It has to be set from outside new.
319 if (m_bExternalTitle)
320 return;
322 css::uno::Reference< css::uno::XInterface > xOwner (m_xOwner.get() , css::uno::UNO_QUERY);
323 css::uno::Reference< css::frame::XUntitledNumbers > xNumbers (m_xUntitledNumbers.get(), css::uno::UNO_QUERY);
324 ::sal_Int32 nLeasedNumber = m_nLeasedNumber;
326 aLock.clear ();
327 // <- SYNCHRONIZED
329 if (
330 ( ! xOwner.is ()) ||
331 ( ! xNumbers.is ()) ||
332 ( ! xModel.is ())
334 return;
336 OUString sTitle;
337 OUString sURL;
339 css::uno::Reference< css::frame::XStorable > xURLProvider(xModel , css::uno::UNO_QUERY);
340 if (xURLProvider.is())
341 sURL = xURLProvider->getLocation ();
343 if (!sURL.isEmpty())
345 sTitle = impl_convertURL2Title(sURL);
346 if (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
347 xNumbers->releaseNumber (nLeasedNumber);
348 nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
350 else
352 if (nLeasedNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
353 nLeasedNumber = xNumbers->leaseNumber (xOwner);
355 OUStringBuffer sNewTitle(256);
356 sNewTitle.append (xNumbers->getUntitledPrefix ());
357 if (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
358 sNewTitle.append ((::sal_Int32)nLeasedNumber);
359 else
360 sNewTitle.appendAscii("?");
362 sTitle = sNewTitle.makeStringAndClear ();
365 // SYNCHRONIZED ->
366 aLock.reset ();
368 // WORKAROUND: the notification is currently sent always,
369 // can be changed after shared mode is supported per UNO API
370 bool bChanged = !init; // && m_sTitle != sTitle
372 m_sTitle = sTitle;
373 m_nLeasedNumber = nLeasedNumber;
375 aLock.clear ();
376 // <- SYNCHRONIZED
378 if (bChanged)
379 impl_sendTitleChangedEvent ();
382 void TitleHelper::impl_updateTitleForController (const css::uno::Reference< css::frame::XController >& xController, bool init)
384 // SYNCHRONIZED ->
385 ::osl::ResettableMutexGuard aLock(m_aMutex);
387 // external title wont be updated internally !
388 // It has to be set from outside new.
389 if (m_bExternalTitle)
390 return;
392 css::uno::Reference< css::uno::XInterface > xOwner (m_xOwner.get() , css::uno::UNO_QUERY);
393 css::uno::Reference< css::frame::XUntitledNumbers > xNumbers (m_xUntitledNumbers.get(), css::uno::UNO_QUERY);
394 ::sal_Int32 nLeasedNumber = m_nLeasedNumber;
396 aLock.clear ();
397 // <- SYNCHRONIZED
399 if (
400 ( ! xOwner.is ()) ||
401 ( ! xNumbers.is ()) ||
402 ( ! xController.is ())
404 return;
406 OUStringBuffer sTitle(256);
408 if (nLeasedNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
409 nLeasedNumber = xNumbers->leaseNumber (xOwner);
411 css::uno::Reference< css::frame::XTitle > xModelTitle(xController->getModel (), css::uno::UNO_QUERY);
412 if (!xModelTitle.is ())
413 xModelTitle.set(xController, css::uno::UNO_QUERY);
414 if (xModelTitle.is ())
416 sTitle.append (xModelTitle->getTitle ());
417 if ( nLeasedNumber > 1 )
419 sTitle.appendAscii (" : ");
420 sTitle.append ((::sal_Int32)nLeasedNumber);
423 else
425 sTitle.append (xNumbers->getUntitledPrefix ());
426 if ( nLeasedNumber > 1 )
428 sTitle.append ((::sal_Int32)nLeasedNumber );
432 // SYNCHRONIZED ->
433 aLock.reset ();
435 OUString sNewTitle = sTitle.makeStringAndClear ();
436 bool bChanged = !init && m_sTitle != sNewTitle;
437 m_sTitle = sNewTitle;
438 m_nLeasedNumber = nLeasedNumber;
440 aLock.clear ();
441 // <- SYNCHRONIZED
443 if (bChanged)
444 impl_sendTitleChangedEvent ();
447 void TitleHelper::impl_updateTitleForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame, bool init)
449 if ( ! xFrame.is ())
450 return;
452 // SYNCHRONIZED ->
453 ::osl::ResettableMutexGuard aLock(m_aMutex);
455 // external title wont be updated internally !
456 // It has to be set from outside new.
457 if (m_bExternalTitle)
458 return;
460 aLock.clear ();
461 // <- SYNCHRONIZED
463 css::uno::Reference< css::uno::XInterface > xComponent;
464 xComponent = xFrame->getController ();
465 if ( ! xComponent.is ())
466 xComponent = xFrame->getComponentWindow ();
468 OUStringBuffer sTitle (256);
470 impl_appendComponentTitle (sTitle, xComponent);
471 #ifndef MACOSX
472 // fdo#70376: We want the window title to contain just the
473 // document name (from the above "component title").
474 impl_appendProductName (sTitle);
475 impl_appendModuleName (sTitle);
476 impl_appendDebugVersion (sTitle);
477 #endif
478 // SYNCHRONIZED ->
479 aLock.reset ();
481 OUString sNewTitle = sTitle.makeStringAndClear ();
482 bool bChanged = !init && m_sTitle != sNewTitle;
483 m_sTitle = sNewTitle;
485 aLock.clear ();
486 // <- SYNCHRONIZED
488 if (bChanged)
489 impl_sendTitleChangedEvent ();
492 void TitleHelper::impl_appendComponentTitle ( OUStringBuffer& sTitle ,
493 const css::uno::Reference< css::uno::XInterface >& xComponent)
495 css::uno::Reference< css::frame::XTitle > xTitle(xComponent, css::uno::UNO_QUERY);
497 // Note: Title has to be used (even if it's empty) if the right interface is supported.
498 if (xTitle.is ())
499 sTitle.append (xTitle->getTitle ());
502 void TitleHelper::impl_appendProductName (OUStringBuffer& sTitle)
504 OUString name(utl::ConfigManager::getProductName());
505 if (!name.isEmpty())
507 if (!sTitle.isEmpty())
508 sTitle.append(" - ");
509 sTitle.append(name);
513 void TitleHelper::impl_appendModuleName (OUStringBuffer& sTitle)
515 // SYNCHRONIZED ->
516 ::osl::ResettableMutexGuard aLock(m_aMutex);
518 css::uno::Reference< css::uno::XInterface > xOwner = m_xOwner.get();
519 css::uno::Reference< css::uno::XComponentContext > xContext = m_xContext;
521 aLock.clear ();
522 // <- SYNCHRONIZED
526 css::uno::Reference< css::frame::XModuleManager2 > xModuleManager =
527 css::frame::ModuleManager::create(xContext);
529 const OUString sID = xModuleManager->identify(xOwner);
530 ::comphelper::SequenceAsHashMap lProps = xModuleManager->getByName (sID);
531 const OUString sUIName = lProps.getUnpackedValueOrDefault (OFFICEFACTORY_PROPNAME_UINAME, OUString());
533 // An UIname property is an optional value !
534 // So please add it to the title in case it does really exists only.
535 if (!sUIName.isEmpty())
537 sTitle.appendAscii (" " );
538 sTitle.append (sUIName);
541 catch(const css::uno::Exception&)
545 #ifdef DBG_UTIL
546 void TitleHelper::impl_appendDebugVersion (OUStringBuffer& sTitle)
548 OUString version(utl::ConfigManager::getProductVersion());
549 sTitle.append(' ');
550 sTitle.append(version);
551 OUString sDefault("development");
552 OUString sVersion = ::utl::Bootstrap::getBuildIdData(sDefault);
553 sTitle.append(" [");
554 sTitle.append(sVersion);
555 sTitle.append("]");
557 #else
558 void TitleHelper::impl_appendDebugVersion (OUStringBuffer&)
561 #endif
563 void TitleHelper::impl_startListeningForModel (const css::uno::Reference< css::frame::XModel >& xModel)
565 css::uno::Reference< css::document::XDocumentEventBroadcaster > xBroadcaster(xModel, css::uno::UNO_QUERY);
566 if ( ! xBroadcaster.is ())
567 return;
569 xBroadcaster->addDocumentEventListener (static_cast< css::document::XDocumentEventListener* >(this));
572 void TitleHelper::impl_startListeningForController (const css::uno::Reference< css::frame::XController >& xController)
574 css::uno::Reference< css::frame::XTitle > xSubTitle(xController->getModel (), css::uno::UNO_QUERY);
575 impl_setSubTitle (xSubTitle);
578 void TitleHelper::impl_startListeningForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame)
580 xFrame->addFrameActionListener(this );
581 impl_updateListeningForFrame (xFrame);
584 void TitleHelper::impl_updateListeningForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame)
586 css::uno::Reference< css::frame::XTitle > xSubTitle(xFrame->getController (), css::uno::UNO_QUERY);
587 impl_setSubTitle (xSubTitle);
590 void TitleHelper::impl_setSubTitle (const css::uno::Reference< css::frame::XTitle >& xSubTitle)
592 // SYNCHRONIZED ->
593 ::osl::ResettableMutexGuard aLock(m_aMutex);
595 // ignore duplicate calls. Makes outside using of this helper more easy :-)
596 css::uno::Reference< css::frame::XTitle > xOldSubTitle(m_xSubTitle.get(), css::uno::UNO_QUERY);
597 if (xOldSubTitle == xSubTitle)
598 return;
600 m_xSubTitle = xSubTitle;
602 aLock.clear ();
603 // <- SYNCHRONIZED
605 css::uno::Reference< css::frame::XTitleChangeBroadcaster > xOldBroadcaster(xOldSubTitle , css::uno::UNO_QUERY );
606 css::uno::Reference< css::frame::XTitleChangeBroadcaster > xNewBroadcaster(xSubTitle , css::uno::UNO_QUERY );
607 css::uno::Reference< css::frame::XTitleChangeListener > xThis (static_cast< css::frame::XTitleChangeListener* >(this), css::uno::UNO_QUERY_THROW);
609 if (xOldBroadcaster.is())
610 xOldBroadcaster->removeTitleChangeListener (xThis);
612 if (xNewBroadcaster.is())
613 xNewBroadcaster->addTitleChangeListener (xThis);
616 OUString TitleHelper::impl_convertURL2Title(const OUString& sURL)
618 INetURLObject aURL (sURL);
619 OUString sTitle;
621 if (aURL.GetProtocol() == INetProtocol::File)
623 if (aURL.HasMark())
624 aURL = INetURLObject(aURL.GetURLNoMark());
626 sTitle = aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET);
628 else
630 if (aURL.hasExtension(INetURLObject::LAST_SEGMENT))
631 sTitle = aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET);
633 if ( sTitle.isEmpty() )
634 sTitle = aURL.GetHostPort(INetURLObject::DECODE_WITH_CHARSET);
636 if ( sTitle.isEmpty() )
637 sTitle = aURL.GetURLNoPass(INetURLObject::DECODE_WITH_CHARSET);
640 return sTitle;
643 } // namespace framework
645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */