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>
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>
40 TitleHelper::TitleHelper(const css::uno::Reference
< css::uno::XComponentContext
>& rxContext
)
41 : ::cppu::BaseMutex ()
42 , m_xContext (rxContext
)
44 , m_xUntitledNumbers()
46 , m_bExternalTitle (false)
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
)
60 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
67 css::uno::Reference
< css::frame::XModel
> xModel(xOwner
, css::uno::UNO_QUERY
);
70 impl_startListeningForModel (xModel
);
74 css::uno::Reference
< css::frame::XController
> xController(xOwner
, css::uno::UNO_QUERY
);
75 if (xController
.is ())
77 impl_startListeningForController (xController
);
81 css::uno::Reference
< css::frame::XFrame
> xFrame(xOwner
, css::uno::UNO_QUERY
);
84 impl_startListeningForFrame (xFrame
);
89 OUString SAL_CALL
TitleHelper::getTitle()
90 throw (css::uno::RuntimeException
, std::exception
)
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 !
101 // Title seems to be up-to-date. Return it directly.
102 if (!m_sTitle
.isEmpty())
105 // Title seems to be unused till now ... do bootstraping
106 impl_updateTitle (true);
113 void TitleHelper::connectWithUntitledNumbers (const css::uno::Reference
< css::frame::XUntitledNumbers
>& xNumbers
)
116 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
118 m_xUntitledNumbers
= xNumbers
;
123 void SAL_CALL
TitleHelper::setTitle(const OUString
& sTitle
)
124 throw (css::uno::RuntimeException
, std::exception
)
127 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
129 m_bExternalTitle
= true;
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
)
156 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
158 css::uno::Reference
< css::frame::XTitle
> xSubTitle(m_xSubTitle
.get (), css::uno::UNO_QUERY
);
163 if (aEvent
.Source
!= xSubTitle
)
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"))
178 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
180 css::uno::Reference
< css::frame::XModel
> xOwner(m_xOwner
.get (), css::uno::UNO_QUERY
);
185 if (aEvent
.Source
!= xOwner
186 || ((aEvent
.EventName
.equalsIgnoreAsciiCase("OnModeChanged")
187 || aEvent
.EventName
.equalsIgnoreAsciiCase("OnTitleChanged"))
196 void SAL_CALL
TitleHelper::frameAction(const css::frame::FrameActionEvent
& aEvent
)
197 throw(css::uno::RuntimeException
, std::exception
)
200 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
202 css::uno::Reference
< css::frame::XFrame
> xOwner(m_xOwner
.get (), css::uno::UNO_QUERY
);
207 if (aEvent
.Source
!= xOwner
)
210 // we are interested on events only, which must trigger a title bar update
211 // because component was changed.
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
);
223 void SAL_CALL
TitleHelper::disposing(const css::lang::EventObject
& aEvent
)
224 throw (css::uno::RuntimeException
, std::exception
)
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
;
237 if (xOwner
!= aEvent
.Source
)
242 (nLeasedNumber
!= css::frame::UntitledNumbersConst::INVALID_NUMBER
)
244 xNumbers
->releaseNumber (nLeasedNumber
);
249 m_sTitle
= OUString ();
250 m_nLeasedNumber
= css::frame::UntitledNumbersConst::INVALID_NUMBER
;
255 impl_sendTitleChangedEvent ();
258 void TitleHelper::impl_sendTitleChangedEvent ()
261 ::osl::ResettableMutexGuard
aLock(m_aMutex
);
263 css::frame::TitleChangedEvent
aEvent(m_xOwner
.get (), m_sTitle
);
268 ::cppu::OInterfaceContainerHelper
* pContainer
= m_aListener
.getContainer( cppu::UnoType
<css::frame::XTitleChangeListener
>::get());
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
&)
286 void TitleHelper::impl_updateTitle (bool init
)
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
);
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
)
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
)
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
;
331 ( ! xNumbers
.is ()) ||
339 css::uno::Reference
< css::frame::XStorable
> xURLProvider(xModel
, css::uno::UNO_QUERY
);
340 if (xURLProvider
.is())
341 sURL
= xURLProvider
->getLocation ();
345 sTitle
= impl_convertURL2Title(sURL
);
346 if (nLeasedNumber
!= css::frame::UntitledNumbersConst::INVALID_NUMBER
)
347 xNumbers
->releaseNumber (nLeasedNumber
);
348 nLeasedNumber
= css::frame::UntitledNumbersConst::INVALID_NUMBER
;
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
);
360 sNewTitle
.appendAscii("?");
362 sTitle
= sNewTitle
.makeStringAndClear ();
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
373 m_nLeasedNumber
= nLeasedNumber
;
379 impl_sendTitleChangedEvent ();
382 void TitleHelper::impl_updateTitleForController (const css::uno::Reference
< css::frame::XController
>& xController
, bool init
)
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
)
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
;
401 ( ! xNumbers
.is ()) ||
402 ( ! xController
.is ())
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
);
425 sTitle
.append (xNumbers
->getUntitledPrefix ());
426 if ( nLeasedNumber
> 1 )
428 sTitle
.append ((::sal_Int32
)nLeasedNumber
);
435 OUString sNewTitle
= sTitle
.makeStringAndClear ();
436 bool bChanged
= !init
&& m_sTitle
!= sNewTitle
;
437 m_sTitle
= sNewTitle
;
438 m_nLeasedNumber
= nLeasedNumber
;
444 impl_sendTitleChangedEvent ();
447 void TitleHelper::impl_updateTitleForFrame (const css::uno::Reference
< css::frame::XFrame
>& xFrame
, bool init
)
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
)
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
);
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
);
481 OUString sNewTitle
= sTitle
.makeStringAndClear ();
482 bool bChanged
= !init
&& m_sTitle
!= sNewTitle
;
483 m_sTitle
= sNewTitle
;
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.
499 sTitle
.append (xTitle
->getTitle ());
502 void TitleHelper::impl_appendProductName (OUStringBuffer
& sTitle
)
504 OUString
name(utl::ConfigManager::getProductName());
507 if (!sTitle
.isEmpty())
508 sTitle
.append(" - ");
513 void TitleHelper::impl_appendModuleName (OUStringBuffer
& sTitle
)
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
;
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
&)
546 void TitleHelper::impl_appendDebugVersion (OUStringBuffer
& sTitle
)
548 OUString
version(utl::ConfigManager::getProductVersion());
550 sTitle
.append(version
);
551 OUString
sDefault("development");
552 OUString sVersion
= ::utl::Bootstrap::getBuildIdData(sDefault
);
554 sTitle
.append(sVersion
);
558 void TitleHelper::impl_appendDebugVersion (OUStringBuffer
&)
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 ())
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
)
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
)
600 m_xSubTitle
= xSubTitle
;
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
);
621 if (aURL
.GetProtocol() == INetProtocol::File
)
624 aURL
= INetURLObject(aURL
.GetURLNoMark());
626 sTitle
= aURL
.getName(INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
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
);
643 } // namespace framework
645 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */