build fix: no comphelper/profilezone.hxx in this branch
[LibreOffice.git] / framework / source / fwe / helper / titlehelper.cxx
blob16ad4b3dafb439d688d96ed927d871d9a57af945
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 <classes/fwkresid.hxx>
22 #include <classes/resource.hrc>
23 #include <services.h>
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>
42 namespace framework{
44 TitleHelper::TitleHelper(const css::uno::Reference< css::uno::XComponentContext >& rxContext)
45 : ::cppu::BaseMutex ()
46 , m_xContext (rxContext)
47 , m_xOwner ()
48 , m_xUntitledNumbers()
49 , m_xSubTitle ()
50 , m_bExternalTitle (false)
51 , m_sTitle ()
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)
63 // SYNCHRONIZED ->
64 ::osl::ResettableMutexGuard aLock(m_aMutex);
66 m_xOwner = xOwner;
68 aLock.clear ();
69 // <- SYNCHRONIZED
71 css::uno::Reference< css::frame::XModel > xModel(xOwner, css::uno::UNO_QUERY);
72 if (xModel.is ())
74 impl_startListeningForModel (xModel);
75 return;
78 css::uno::Reference< css::frame::XController > xController(xOwner, css::uno::UNO_QUERY);
79 if (xController.is ())
81 impl_startListeningForController (xController);
82 return;
85 css::uno::Reference< css::frame::XFrame > xFrame(xOwner, css::uno::UNO_QUERY);
86 if (xFrame.is ())
88 impl_startListeningForFrame (xFrame);
89 return;
93 OUString SAL_CALL TitleHelper::getTitle()
94 throw (css::uno::RuntimeException, std::exception)
96 // SYNCHRONIZED ->
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)
103 return m_sTitle;
105 // Title seems to be up-to-date. Return it directly.
106 if (!m_sTitle.isEmpty())
107 return m_sTitle;
109 // Title seems to be unused till now ... do bootstraping
110 impl_updateTitle (true);
112 return m_sTitle;
114 // <- SYNCHRONIZED
117 void TitleHelper::connectWithUntitledNumbers (const css::uno::Reference< css::frame::XUntitledNumbers >& xNumbers)
119 // SYNCHRONIZED ->
120 ::osl::ResettableMutexGuard aLock(m_aMutex);
122 m_xUntitledNumbers = xNumbers;
124 // <- SYNCHRONIZED
127 void SAL_CALL TitleHelper::setTitle(const OUString& sTitle)
128 throw (css::uno::RuntimeException, std::exception)
130 // SYNCHRONIZED ->
131 ::osl::ResettableMutexGuard aLock(m_aMutex);
133 m_bExternalTitle = true;
134 m_sTitle = sTitle;
136 aLock.clear ();
137 // <- SYNCHRONIZED
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)
159 // SYNCHRONIZED ->
160 ::osl::ResettableMutexGuard aLock(m_aMutex);
162 css::uno::Reference< css::frame::XTitle > xSubTitle(m_xSubTitle.get (), css::uno::UNO_QUERY);
164 aLock.clear ();
165 // <- SYNCHRONIZED
167 if (aEvent.Source != xSubTitle)
168 return;
170 impl_updateTitle ();
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"))
179 return;
181 // SYNCHRONIZED ->
182 ::osl::ResettableMutexGuard aLock(m_aMutex);
184 css::uno::Reference< css::frame::XModel > xOwner(m_xOwner.get (), css::uno::UNO_QUERY);
186 aLock.clear ();
187 // <- SYNCHRONIZED
189 if (aEvent.Source != xOwner
190 || ((aEvent.EventName.equalsIgnoreAsciiCase("OnModeChanged")
191 || aEvent.EventName.equalsIgnoreAsciiCase("OnTitleChanged"))
192 && !xOwner.is()))
194 return;
197 impl_updateTitle ();
200 void SAL_CALL TitleHelper::frameAction(const css::frame::FrameActionEvent& aEvent)
201 throw(css::uno::RuntimeException, std::exception)
203 // SYNCHRONIZED ->
204 ::osl::ResettableMutexGuard aLock(m_aMutex);
206 css::uno::Reference< css::frame::XFrame > xOwner(m_xOwner.get (), css::uno::UNO_QUERY);
208 aLock.clear ();
209 // <- SYNCHRONIZED
211 if (aEvent.Source != xOwner)
212 return;
214 // we are interested on events only, which must trigger a title bar update
215 // because component was changed.
216 if (
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);
223 impl_updateTitle ();
227 void SAL_CALL TitleHelper::disposing(const css::lang::EventObject& aEvent)
228 throw (css::uno::RuntimeException, std::exception)
230 // SYNCHRONIZED ->
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;
235 aLock.clear ();
236 // <- SYNCHRONIZED
238 if ( ! xOwner.is ())
239 return;
241 if (xOwner != aEvent.Source)
242 return;
244 if (
245 (xNumbers.is () ) &&
246 (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
248 xNumbers->releaseNumber (nLeasedNumber);
250 // SYNCHRONIZED ->
251 aLock.reset ();
253 m_xOwner = nullptr;
254 m_sTitle = OUString ();
255 m_nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
257 aLock.clear ();
258 // <- SYNCHRONIZED
262 void TitleHelper::impl_sendTitleChangedEvent ()
264 // SYNCHRONIZED ->
265 ::osl::ResettableMutexGuard aLock(m_aMutex);
267 css::frame::TitleChangedEvent aEvent(m_xOwner.get (), m_sTitle);
269 aLock.clear ();
270 // <- SYNCHRONIZED
272 if( ! (aEvent.Source).is() )
273 return;
275 ::cppu::OInterfaceContainerHelper* pContainer = m_aListener.getContainer( cppu::UnoType<css::frame::XTitleChangeListener>::get());
276 if ( ! pContainer)
277 return;
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&)
288 pIt.remove();
293 void TitleHelper::impl_updateTitle (bool init)
295 // SYNCHRONIZED ->
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);
302 aLock.clear ();
303 // <- SYNCHRONIZED
305 if (xModel.is ())
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)
321 // SYNCHRONIZED ->
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)
327 return;
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;
333 aLock.clear ();
334 // <- SYNCHRONIZED
336 if (
337 ( ! xOwner.is ()) ||
338 ( ! xNumbers.is ()) ||
339 ( ! xModel.is ())
341 return;
343 OUString sTitle;
344 OUString sURL;
346 css::uno::Reference< css::frame::XStorable > xURLProvider(xModel , css::uno::UNO_QUERY);
347 if (xURLProvider.is())
348 sURL = xURLProvider->getLocation ();
350 if (!sURL.isEmpty())
352 sTitle = impl_convertURL2Title(sURL);
353 if (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
354 xNumbers->releaseNumber (nLeasedNumber);
355 nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
357 else
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);
366 else
367 sNewTitle.append("?");
369 sTitle = sNewTitle.makeStringAndClear ();
372 // SYNCHRONIZED ->
373 aLock.reset ();
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
379 m_sTitle = sTitle;
380 m_nLeasedNumber = nLeasedNumber;
382 aLock.clear ();
383 // <- SYNCHRONIZED
385 if (bChanged)
386 impl_sendTitleChangedEvent ();
389 void TitleHelper::impl_updateTitleForController (const css::uno::Reference< css::frame::XController >& xController, bool init)
391 // SYNCHRONIZED ->
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)
397 return;
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;
403 aLock.clear ();
404 // <- SYNCHRONIZED
406 if (
407 ( ! xOwner.is ()) ||
408 ( ! xNumbers.is ()) ||
409 ( ! xController.is ())
411 return;
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);
430 if (xModel.is ())
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);
441 else
443 sTitle.append (xNumbers->getUntitledPrefix ());
444 if ( nLeasedNumber > 1 )
446 sTitle.append ((::sal_Int32)nLeasedNumber );
450 // SYNCHRONIZED ->
451 aLock.reset ();
453 OUString sNewTitle = sTitle.makeStringAndClear ();
454 bool bChanged = !init && m_sTitle != sNewTitle;
455 m_sTitle = sNewTitle;
456 m_nLeasedNumber = nLeasedNumber;
458 aLock.clear ();
459 // <- SYNCHRONIZED
461 if (bChanged)
462 impl_sendTitleChangedEvent ();
465 void TitleHelper::impl_updateTitleForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame, bool init)
467 if ( ! xFrame.is ())
468 return;
470 // SYNCHRONIZED ->
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)
476 return;
478 aLock.clear ();
479 // <- SYNCHRONIZED
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);
489 #ifndef MACOSX
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);
495 #endif
496 impl_appendSafeMode (sTitle);
497 // SYNCHRONIZED ->
498 aLock.reset ();
500 OUString sNewTitle = sTitle.makeStringAndClear ();
501 bool bChanged = !init && m_sTitle != sNewTitle;
502 m_sTitle = sNewTitle;
504 aLock.clear ();
505 // <- SYNCHRONIZED
507 if (bChanged)
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.
517 if (xTitle.is ())
518 sTitle.append (xTitle->getTitle ());
521 void TitleHelper::impl_appendProductName (OUStringBuffer& sTitle)
523 OUString name(utl::ConfigManager::getProductName());
524 if (!name.isEmpty())
526 if (!sTitle.isEmpty())
527 sTitle.append(" - ");
528 sTitle.append(name);
532 void TitleHelper::impl_appendModuleName (OUStringBuffer& sTitle)
534 // SYNCHRONIZED ->
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;
540 aLock.clear ();
541 // <- SYNCHRONIZED
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&)
564 #ifdef DBG_UTIL
565 void TitleHelper::impl_appendDebugVersion (OUStringBuffer& sTitle)
567 OUString version(utl::ConfigManager::getProductVersion());
568 sTitle.append(' ');
569 sTitle.append(version);
570 OUString sDefault("development");
571 OUString sVersion = ::utl::Bootstrap::getBuildIdData(sDefault);
572 sTitle.append(" [");
573 sTitle.append(sVersion);
574 if (OpenGLWrapper::isVCLOpenGLEnabled())
575 sTitle.append("-GL");
576 sTitle.append("]");
578 #else
579 void TitleHelper::impl_appendDebugVersion (OUStringBuffer&)
582 #endif
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 ())
594 return;
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)
620 // SYNCHRONIZED ->
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)
626 return;
628 m_xSubTitle = xSubTitle;
630 aLock.clear ();
631 // <- SYNCHRONIZED
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);
647 OUString sTitle;
649 if (aURL.GetProtocol() == INetProtocol::File)
651 if (aURL.HasMark())
652 aURL = INetURLObject(aURL.GetURLNoMark());
654 sTitle = aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset);
656 else
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);
668 return sTitle;
671 } // namespace framework
673 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */