1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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 <classes/fwkresid.hxx>
22 #include <classes/resource.hrc>
24 #include <properties.h>
26 #include <com/sun/star/frame/UntitledNumbersConst.hpp>
27 #include <com/sun/star/frame/XStorable.hpp>
28 #include <com/sun/star/frame/ModuleManager.hpp>
29 #include <com/sun/star/container/XNameAccess.hpp>
30 #include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
31 #include <com/sun/star/beans/XMaterialHolder.hpp>
33 #include <unotools/configmgr.hxx>
34 #include <unotools/bootstrap.hxx>
35 #include <comphelper/sequenceashashmap.hxx>
36 #include <rtl/ustrbuf.hxx>
37 #include <osl/mutex.hxx>
38 #include <tools/urlobj.hxx>
39 #include <vcl/opengl/OpenGLWrapper.hxx>
40 #include <vcl/svapp.hxx>
44 TitleHelper::TitleHelper(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
)
45 : ::cppu::BaseMutex ()
46 , m_xContext (rxContext
)
48 , m_xUntitledNumbers()
50 , m_bExternalTitle (false)
52 , m_nLeasedNumber (css::frame::UntitledNumbersConst::INVALID_NUMBER
)
53 , m_aListener (m_aMutex
)
57 TitleHelper::~TitleHelper()
61 void TitleHelper::setOwner(const css::uno::Reference
< css::uno::XInterface
>& xOwner
)
64 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
71 css::uno::Reference
< css::frame::XModel
> xModel(xOwner
, css::uno::UNO_QUERY
);
74 impl_startListeningForModel (xModel
);
78 css::uno::Reference
< css::frame::XController
> xController(xOwner
, css::uno::UNO_QUERY
);
79 if (xController
.is ())
81 impl_startListeningForController (xController
);
85 css::uno::Reference
< css::frame::XFrame
> xFrame(xOwner
, css::uno::UNO_QUERY
);
88 impl_startListeningForFrame (xFrame
);
93 OUString SAL_CALL
TitleHelper::getTitle()
94 throw (css::uno::RuntimeException
, std::exception
)
97 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
99 // An external title will win always and disable all internal logic about
100 // creating/using a title value.
101 // Even an empty string will be accepted as valid title !
102 if (m_bExternalTitle
)
105 // Title seems to be up-to-date. Return it directly.
106 if (!m_sTitle
.isEmpty())
109 // Title seems to be unused till now ... do bootstraping
110 impl_updateTitle (true);
117 void TitleHelper::connectWithUntitledNumbers (const css::uno::Reference
< css::frame::XUntitledNumbers
>& xNumbers
)
120 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
122 m_xUntitledNumbers
= xNumbers
;
127 void SAL_CALL
TitleHelper::setTitle(const OUString
& sTitle
)
128 throw (css::uno::RuntimeException
, std::exception
)
131 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
133 m_bExternalTitle
= true;
139 impl_sendTitleChangedEvent ();
142 void SAL_CALL
TitleHelper::addTitleChangeListener(const css::uno::Reference
< css::frame::XTitleChangeListener
>& xListener
)
143 throw (css::uno::RuntimeException
, std::exception
)
145 // container is threadsafe by himself
146 m_aListener
.addInterface( cppu::UnoType
<css::frame::XTitleChangeListener
>::get(), xListener
);
149 void SAL_CALL
TitleHelper::removeTitleChangeListener(const css::uno::Reference
< css::frame::XTitleChangeListener
>& xListener
)
150 throw (css::uno::RuntimeException
, std::exception
)
152 // container is threadsafe by himself
153 m_aListener
.removeInterface( cppu::UnoType
<css::frame::XTitleChangeListener
>::get(), xListener
);
156 void SAL_CALL
TitleHelper::titleChanged(const css::frame::TitleChangedEvent
& aEvent
)
157 throw (css::uno::RuntimeException
, std::exception
)
160 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
162 css::uno::Reference
< css::frame::XTitle
> xSubTitle(m_xSubTitle
.get (), css::uno::UNO_QUERY
);
167 if (aEvent
.Source
!= xSubTitle
)
173 void SAL_CALL
TitleHelper::documentEventOccured(const css::document::DocumentEvent
& aEvent
)
174 throw (css::uno::RuntimeException
, std::exception
)
176 if ( ! aEvent
.EventName
.equalsIgnoreAsciiCase("OnSaveAsDone")
177 && ! aEvent
.EventName
.equalsIgnoreAsciiCase("OnModeChanged")
178 && ! aEvent
.EventName
.equalsIgnoreAsciiCase("OnTitleChanged"))
182 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
184 css::uno::Reference
< css::frame::XModel
> xOwner(m_xOwner
.get (), css::uno::UNO_QUERY
);
189 if (aEvent
.Source
!= xOwner
190 || ((aEvent
.EventName
.equalsIgnoreAsciiCase("OnModeChanged")
191 || aEvent
.EventName
.equalsIgnoreAsciiCase("OnTitleChanged"))
200 void SAL_CALL
TitleHelper::frameAction(const css::frame::FrameActionEvent
& aEvent
)
201 throw(css::uno::RuntimeException
, std::exception
)
204 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
206 css::uno::Reference
< css::frame::XFrame
> xOwner(m_xOwner
.get (), css::uno::UNO_QUERY
);
211 if (aEvent
.Source
!= xOwner
)
214 // we are interested on events only, which must trigger a title bar update
215 // because component was changed.
217 (aEvent
.Action
== css::frame::FrameAction_COMPONENT_ATTACHED
) ||
218 (aEvent
.Action
== css::frame::FrameAction_COMPONENT_REATTACHED
) ||
219 (aEvent
.Action
== css::frame::FrameAction_COMPONENT_DETACHING
)
222 impl_updateListeningForFrame (xOwner
);
227 void SAL_CALL
TitleHelper::disposing(const css::lang::EventObject
& aEvent
)
228 throw (css::uno::RuntimeException
, std::exception
)
231 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
232 css::uno::Reference
< css::uno::XInterface
> xOwner (m_xOwner
.get() , css::uno::UNO_QUERY
);
233 css::uno::Reference
< css::frame::XUntitledNumbers
> xNumbers (m_xUntitledNumbers
.get(), css::uno::UNO_QUERY
);
234 ::sal_Int32 nLeasedNumber
= m_nLeasedNumber
;
241 if (xOwner
!= aEvent
.Source
)
246 (nLeasedNumber
!= css::frame::UntitledNumbersConst::INVALID_NUMBER
)
248 xNumbers
->releaseNumber (nLeasedNumber
);
254 m_sTitle
= OUString ();
255 m_nLeasedNumber
= css::frame::UntitledNumbersConst::INVALID_NUMBER
;
262 void TitleHelper::impl_sendTitleChangedEvent ()
265 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
267 css::frame::TitleChangedEvent
aEvent(m_xOwner
.get (), m_sTitle
);
272 if( ! (aEvent
.Source
).is() )
275 ::cppu::OInterfaceContainerHelper
* pContainer
= m_aListener
.getContainer( cppu::UnoType
<css::frame::XTitleChangeListener
>::get());
279 ::cppu::OInterfaceIteratorHelper
pIt( *pContainer
);
280 while ( pIt
.hasMoreElements() )
284 static_cast<css::frame::XTitleChangeListener
*>(pIt
.next())->titleChanged( aEvent
);
286 catch(const css::uno::Exception
&)
293 void TitleHelper::impl_updateTitle (bool init
)
296 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
298 css::uno::Reference
< css::frame::XModel
> xModel (m_xOwner
.get(), css::uno::UNO_QUERY
);
299 css::uno::Reference
< css::frame::XController
> xController(m_xOwner
.get(), css::uno::UNO_QUERY
);
300 css::uno::Reference
< css::frame::XFrame
> xFrame (m_xOwner
.get(), css::uno::UNO_QUERY
);
307 impl_updateTitleForModel (xModel
, init
);
309 else if (xController
.is ())
311 impl_updateTitleForController (xController
, init
);
313 else if (xFrame
.is ())
315 impl_updateTitleForFrame (xFrame
, init
);
319 void TitleHelper::impl_updateTitleForModel (const css::uno::Reference
< css::frame::XModel
>& xModel
, bool init
)
322 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
324 // external title won't be updated internally!
325 // It has to be set from outside new.
326 if (m_bExternalTitle
)
329 css::uno::Reference
< css::uno::XInterface
> xOwner (m_xOwner
.get() , css::uno::UNO_QUERY
);
330 css::uno::Reference
< css::frame::XUntitledNumbers
> xNumbers (m_xUntitledNumbers
.get(), css::uno::UNO_QUERY
);
331 ::sal_Int32 nLeasedNumber
= m_nLeasedNumber
;
338 ( ! xNumbers
.is ()) ||
346 css::uno::Reference
< css::frame::XStorable
> xURLProvider(xModel
, css::uno::UNO_QUERY
);
347 if (xURLProvider
.is())
348 sURL
= xURLProvider
->getLocation ();
352 sTitle
= impl_convertURL2Title(sURL
);
353 if (nLeasedNumber
!= css::frame::UntitledNumbersConst::INVALID_NUMBER
)
354 xNumbers
->releaseNumber (nLeasedNumber
);
355 nLeasedNumber
= css::frame::UntitledNumbersConst::INVALID_NUMBER
;
359 if (nLeasedNumber
== css::frame::UntitledNumbersConst::INVALID_NUMBER
)
360 nLeasedNumber
= xNumbers
->leaseNumber (xOwner
);
362 OUStringBuffer
sNewTitle(256);
363 sNewTitle
.append (xNumbers
->getUntitledPrefix ());
364 if (nLeasedNumber
!= css::frame::UntitledNumbersConst::INVALID_NUMBER
)
365 sNewTitle
.append ((::sal_Int32
)nLeasedNumber
);
367 sNewTitle
.append("?");
369 sTitle
= sNewTitle
.makeStringAndClear ();
375 // WORKAROUND: the notification is currently sent always,
376 // can be changed after shared mode is supported per UNO API
377 bool bChanged
= !init
; // && m_sTitle != sTitle
380 m_nLeasedNumber
= nLeasedNumber
;
386 impl_sendTitleChangedEvent ();
389 void TitleHelper::impl_updateTitleForController (const css::uno::Reference
< css::frame::XController
>& xController
, bool init
)
392 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
394 // external title won't be updated internally!
395 // It has to be set from outside new.
396 if (m_bExternalTitle
)
399 css::uno::Reference
< css::uno::XInterface
> xOwner (m_xOwner
.get() , css::uno::UNO_QUERY
);
400 css::uno::Reference
< css::frame::XUntitledNumbers
> xNumbers (m_xUntitledNumbers
.get(), css::uno::UNO_QUERY
);
401 ::sal_Int32 nLeasedNumber
= m_nLeasedNumber
;
408 ( ! xNumbers
.is ()) ||
409 ( ! xController
.is ())
413 OUStringBuffer
sTitle(256);
415 if (nLeasedNumber
== css::frame::UntitledNumbersConst::INVALID_NUMBER
)
416 nLeasedNumber
= xNumbers
->leaseNumber (xOwner
);
418 css::uno::Reference
< css::frame::XTitle
> xModelTitle(xController
->getModel (), css::uno::UNO_QUERY
);
419 css::uno::Reference
< css::frame::XModel
> xModel(xController
->getModel (), css::uno::UNO_QUERY
);
420 if (!xModelTitle
.is ())
421 xModelTitle
.set(xController
, css::uno::UNO_QUERY
);
422 if (xModelTitle
.is ())
424 sTitle
.append (xModelTitle
->getTitle ());
425 if ( nLeasedNumber
> 1 )
427 sTitle
.append (" : ");
428 sTitle
.append ((::sal_Int32
)nLeasedNumber
);
432 INetURLObject
aURL (xModel
->getURL ());
433 if (aURL
.GetProtocol () != INetProtocol::File
434 && aURL
.GetProtocol () != INetProtocol::NotValid
)
436 OUString
sRemoteText (FwkResId (STR_REMOTE_TITLE
));
437 sTitle
.append (sRemoteText
);
443 sTitle
.append (xNumbers
->getUntitledPrefix ());
444 if ( nLeasedNumber
> 1 )
446 sTitle
.append ((::sal_Int32
)nLeasedNumber
);
453 OUString sNewTitle
= sTitle
.makeStringAndClear ();
454 bool bChanged
= !init
&& m_sTitle
!= sNewTitle
;
455 m_sTitle
= sNewTitle
;
456 m_nLeasedNumber
= nLeasedNumber
;
462 impl_sendTitleChangedEvent ();
465 void TitleHelper::impl_updateTitleForFrame (const css::uno::Reference
< css::frame::XFrame
>& xFrame
, bool init
)
471 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
473 // external title won't be updated internally!
474 // It has to be set from outside new.
475 if (m_bExternalTitle
)
481 css::uno::Reference
< css::uno::XInterface
> xComponent
;
482 xComponent
= xFrame
->getController ();
483 if ( ! xComponent
.is ())
484 xComponent
= xFrame
->getComponentWindow ();
486 OUStringBuffer
sTitle (256);
488 impl_appendComponentTitle (sTitle
, xComponent
);
490 // fdo#70376: We want the window title to contain just the
491 // document name (from the above "component title").
492 impl_appendProductName (sTitle
);
493 impl_appendModuleName (sTitle
);
494 impl_appendDebugVersion (sTitle
);
496 impl_appendSafeMode (sTitle
);
500 OUString sNewTitle
= sTitle
.makeStringAndClear ();
501 bool bChanged
= !init
&& m_sTitle
!= sNewTitle
;
502 m_sTitle
= sNewTitle
;
508 impl_sendTitleChangedEvent ();
511 void TitleHelper::impl_appendComponentTitle ( OUStringBuffer
& sTitle
,
512 const css::uno::Reference
< css::uno::XInterface
>& xComponent
)
514 css::uno::Reference
< css::frame::XTitle
> xTitle(xComponent
, css::uno::UNO_QUERY
);
516 // Note: Title has to be used (even if it's empty) if the right interface is supported.
518 sTitle
.append (xTitle
->getTitle ());
521 void TitleHelper::impl_appendProductName (OUStringBuffer
& sTitle
)
523 OUString
name(utl::ConfigManager::getProductName());
526 if (!sTitle
.isEmpty())
527 sTitle
.append(" - ");
532 void TitleHelper::impl_appendModuleName (OUStringBuffer
& sTitle
)
535 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
537 css::uno::Reference
< css::uno::XInterface
> xOwner
= m_xOwner
.get();
538 css::uno::Reference
< css::uno::XComponentContext
> xContext
= m_xContext
;
545 css::uno::Reference
< css::frame::XModuleManager2
> xModuleManager
=
546 css::frame::ModuleManager::create(xContext
);
548 const OUString sID
= xModuleManager
->identify(xOwner
);
549 ::comphelper::SequenceAsHashMap lProps
= xModuleManager
->getByName (sID
);
550 const OUString sUIName
= lProps
.getUnpackedValueOrDefault (OFFICEFACTORY_PROPNAME_ASCII_UINAME
, OUString());
552 // An UIname property is an optional value !
553 // So please add it to the title in case it does really exists only.
554 if (!sUIName
.isEmpty())
556 sTitle
.append (" " );
557 sTitle
.append (sUIName
);
560 catch(const css::uno::Exception
&)
565 void TitleHelper::impl_appendDebugVersion (OUStringBuffer
& sTitle
)
567 OUString
version(utl::ConfigManager::getProductVersion());
569 sTitle
.append(version
);
570 OUString
sDefault("development");
571 OUString sVersion
= ::utl::Bootstrap::getBuildIdData(sDefault
);
573 sTitle
.append(sVersion
);
574 if (OpenGLWrapper::isVCLOpenGLEnabled())
575 sTitle
.append("-GL");
579 void TitleHelper::impl_appendDebugVersion (OUStringBuffer
&)
584 void TitleHelper::impl_appendSafeMode (OUStringBuffer
& sTitle
)
586 if (Application::IsSafeModeEnabled())
587 sTitle
.append(FwkResId (STR_SAFEMODE_TITLE
));
590 void TitleHelper::impl_startListeningForModel (const css::uno::Reference
< css::frame::XModel
>& xModel
)
592 css::uno::Reference
< css::document::XDocumentEventBroadcaster
> xBroadcaster(xModel
, css::uno::UNO_QUERY
);
593 if ( ! xBroadcaster
.is ())
596 xBroadcaster
->addDocumentEventListener (static_cast< css::document::XDocumentEventListener
* >(this));
599 void TitleHelper::impl_startListeningForController (const css::uno::Reference
< css::frame::XController
>& xController
)
601 xController
->addEventListener (static_cast< css::lang::XEventListener
* > (static_cast< css::frame::XFrameActionListener
* > (this) ) );
602 css::uno::Reference
< css::frame::XTitle
> xSubTitle(xController
->getModel (), css::uno::UNO_QUERY
);
603 impl_setSubTitle (xSubTitle
);
606 void TitleHelper::impl_startListeningForFrame (const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
608 xFrame
->addFrameActionListener(this );
609 impl_updateListeningForFrame (xFrame
);
612 void TitleHelper::impl_updateListeningForFrame (const css::uno::Reference
< css::frame::XFrame
>& xFrame
)
614 css::uno::Reference
< css::frame::XTitle
> xSubTitle(xFrame
->getController (), css::uno::UNO_QUERY
);
615 impl_setSubTitle (xSubTitle
);
618 void TitleHelper::impl_setSubTitle (const css::uno::Reference
< css::frame::XTitle
>& xSubTitle
)
621 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
623 // ignore duplicate calls. Makes outside using of this helper more easy :-)
624 css::uno::Reference
< css::frame::XTitle
> xOldSubTitle(m_xSubTitle
.get(), css::uno::UNO_QUERY
);
625 if (xOldSubTitle
== xSubTitle
)
628 m_xSubTitle
= xSubTitle
;
633 css::uno::Reference
< css::frame::XTitleChangeBroadcaster
> xOldBroadcaster(xOldSubTitle
, css::uno::UNO_QUERY
);
634 css::uno::Reference
< css::frame::XTitleChangeBroadcaster
> xNewBroadcaster(xSubTitle
, css::uno::UNO_QUERY
);
635 css::uno::Reference
< css::frame::XTitleChangeListener
> xThis (static_cast< css::frame::XTitleChangeListener
* >(this), css::uno::UNO_QUERY_THROW
);
637 if (xOldBroadcaster
.is())
638 xOldBroadcaster
->removeTitleChangeListener (xThis
);
640 if (xNewBroadcaster
.is())
641 xNewBroadcaster
->addTitleChangeListener (xThis
);
644 OUString
TitleHelper::impl_convertURL2Title(const OUString
& sURL
)
646 INetURLObject
aURL (sURL
);
649 if (aURL
.GetProtocol() == INetProtocol::File
)
652 aURL
= INetURLObject(aURL
.GetURLNoMark());
654 sTitle
= aURL
.getName(INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
658 if (aURL
.hasExtension())
659 sTitle
= aURL
.getName(INetURLObject::LAST_SEGMENT
, true, INetURLObject::DecodeMechanism::WithCharset
);
661 if ( sTitle
.isEmpty() )
662 sTitle
= aURL
.GetHostPort(INetURLObject::DecodeMechanism::WithCharset
);
664 if ( sTitle
.isEmpty() )
665 sTitle
= aURL
.GetURLNoPass(INetURLObject::DecodeMechanism::WithCharset
);
671 } // namespace framework
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */