Coverage Report

Created: 2026-04-09 11:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/framework/source/fwe/helper/titlehelper.cxx
Line
Count
Source
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
#include <framework/titlehelper.hxx>
21
#include <classes/fwkresid.hxx>
22
#include <strings.hrc>
23
#include <properties.h>
24
25
#include <com/sun/star/frame/UntitledNumbersConst.hpp>
26
#include <com/sun/star/frame/XStorable.hpp>
27
#include <com/sun/star/frame/ModuleManager.hpp>
28
#include <com/sun/star/frame/XUntitledNumbers.hpp>
29
#include <com/sun/star/frame/XModel3.hpp>
30
#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
31
32
#include <comphelper/configuration.hxx>
33
#include <unotools/configmgr.hxx>
34
#include <unotools/bootstrap.hxx>
35
#include <unotools/mediadescriptor.hxx>
36
#include <comphelper/sequenceashashmap.hxx>
37
#include <rtl/ustrbuf.hxx>
38
#include <osl/mutex.hxx>
39
#include <tools/urlobj.hxx>
40
#include <utility>
41
#include <vcl/svapp.hxx>
42
43
44
using namespace css;
45
using namespace css::uno;
46
using namespace css::frame;
47
48
namespace framework{
49
50
TitleHelper::TitleHelper(css::uno::Reference< css::uno::XComponentContext > xContext,
51
                        const css::uno::Reference< css::uno::XInterface >& xOwner,
52
                        const css::uno::Reference< css::frame::XUntitledNumbers >& xNumbers)
53
    :
54
16.0k
      m_xContext        (std::move(xContext))
55
16.0k
    , m_xOwner          (xOwner)
56
16.0k
    , m_xUntitledNumbers(xNumbers)
57
16.0k
    , m_bExternalTitle  (false)
58
16.0k
    , m_nLeasedNumber   (css::frame::UntitledNumbersConst::INVALID_NUMBER)
59
16.0k
{
60
16.0k
    if (css::uno::Reference<css::frame::XModel> xModel{ xOwner, css::uno::UNO_QUERY })
61
3.93k
    {
62
3.93k
        impl_startListeningForModel (xModel);
63
3.93k
    }
64
12.1k
    else if (css::uno::Reference<css::frame::XController> xController{ xOwner,
65
12.1k
                                                                       css::uno::UNO_QUERY })
66
3.93k
    {
67
3.93k
        impl_startListeningForController (xController);
68
3.93k
    }
69
8.22k
    else if (css::uno::Reference<css::frame::XFrame> xFrame{ xOwner, css::uno::UNO_QUERY })
70
8.22k
    {
71
8.22k
        impl_startListeningForFrame (xFrame);
72
8.22k
    }
73
16.0k
}
Unexecuted instantiation: framework::TitleHelper::TitleHelper(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext>, com::sun::star::uno::Reference<com::sun::star::uno::XInterface> const&, com::sun::star::uno::Reference<com::sun::star::frame::XUntitledNumbers> const&)
framework::TitleHelper::TitleHelper(com::sun::star::uno::Reference<com::sun::star::uno::XComponentContext>, com::sun::star::uno::Reference<com::sun::star::uno::XInterface> const&, com::sun::star::uno::Reference<com::sun::star::frame::XUntitledNumbers> const&)
Line
Count
Source
54
16.0k
      m_xContext        (std::move(xContext))
55
16.0k
    , m_xOwner          (xOwner)
56
16.0k
    , m_xUntitledNumbers(xNumbers)
57
16.0k
    , m_bExternalTitle  (false)
58
16.0k
    , m_nLeasedNumber   (css::frame::UntitledNumbersConst::INVALID_NUMBER)
59
16.0k
{
60
16.0k
    if (css::uno::Reference<css::frame::XModel> xModel{ xOwner, css::uno::UNO_QUERY })
61
3.93k
    {
62
3.93k
        impl_startListeningForModel (xModel);
63
3.93k
    }
64
12.1k
    else if (css::uno::Reference<css::frame::XController> xController{ xOwner,
65
12.1k
                                                                       css::uno::UNO_QUERY })
66
3.93k
    {
67
3.93k
        impl_startListeningForController (xController);
68
3.93k
    }
69
8.22k
    else if (css::uno::Reference<css::frame::XFrame> xFrame{ xOwner, css::uno::UNO_QUERY })
70
8.22k
    {
71
8.22k
        impl_startListeningForFrame (xFrame);
72
8.22k
    }
73
16.0k
}
74
75
TitleHelper::~TitleHelper()
76
3.93k
{
77
3.93k
}
78
79
OUString SAL_CALL TitleHelper::getTitle()
80
23.6k
{
81
    // SYNCHRONIZED ->
82
23.6k
    std::unique_lock aLock(m_aMutex);
83
84
    // An external title will win always and disable all internal logic about
85
    // creating/using a title value.
86
    // Even an empty string will be accepted as valid title !
87
23.6k
    if (m_bExternalTitle)
88
0
        return m_sTitle;
89
90
    // Title seems to be up-to-date. Return it directly.
91
23.6k
    if (!m_sTitle.isEmpty())
92
11.8k
        return m_sTitle;
93
94
    // Title seems to be unused till now ... do bootstrapping
95
11.8k
    aLock.unlock();
96
11.8k
    impl_updateTitle (true);
97
11.8k
    aLock.lock();
98
99
11.8k
    return m_sTitle;
100
    // <- SYNCHRONIZED
101
23.6k
}
102
103
void SAL_CALL TitleHelper::setTitle(const OUString& sTitle)
104
0
{
105
    // SYNCHRONIZED ->
106
0
    {
107
0
        std::unique_lock aLock(m_aMutex);
108
109
0
        m_bExternalTitle = true;
110
0
        m_sTitle         = sTitle;
111
0
    }
112
    // <- SYNCHRONIZED
113
114
0
    impl_sendTitleChangedEvent ();
115
0
}
116
117
void SAL_CALL TitleHelper::addTitleChangeListener(const css::uno::Reference< css::frame::XTitleChangeListener >& xListener)
118
16.0k
{
119
16.0k
    std::unique_lock aLock(m_aMutex);
120
16.0k
    m_aTitleChangeListeners.addInterface( aLock, xListener );
121
16.0k
}
122
123
void SAL_CALL TitleHelper::removeTitleChangeListener(const css::uno::Reference< css::frame::XTitleChangeListener >& xListener)
124
0
{
125
0
    std::unique_lock aLock(m_aMutex);
126
0
    m_aTitleChangeListeners.removeInterface( aLock, xListener );
127
0
}
128
129
void SAL_CALL TitleHelper::titleChanged(const css::frame::TitleChangedEvent& aEvent)
130
0
{
131
0
    css::uno::Reference< css::frame::XTitle > xSubTitle;
132
    // SYNCHRONIZED ->
133
0
    {
134
0
        std::unique_lock aLock(m_aMutex);
135
136
0
        xSubTitle = m_xSubTitle;
137
0
    }
138
    // <- SYNCHRONIZED
139
140
0
    if (aEvent.Source != xSubTitle)
141
0
        return;
142
143
0
    impl_updateTitle ();
144
0
}
145
146
void SAL_CALL TitleHelper::documentEventOccured(const css::document::DocumentEvent& aEvent)
147
0
{
148
0
    if ( ! aEvent.EventName.equalsIgnoreAsciiCase("OnSaveAsDone")
149
0
      && ! aEvent.EventName.equalsIgnoreAsciiCase("OnModeChanged")
150
0
      && ! aEvent.EventName.equalsIgnoreAsciiCase("OnTitleChanged"))
151
0
        return;
152
153
0
    css::uno::Reference< css::frame::XModel > xOwner;
154
    // SYNCHRONIZED ->
155
0
    {
156
0
        std::unique_lock aLock(m_aMutex);
157
158
0
        xOwner.set(m_xOwner, css::uno::UNO_QUERY);
159
0
    }
160
    // <- SYNCHRONIZED
161
162
0
    if (aEvent.Source != xOwner
163
0
        || ((aEvent.EventName.equalsIgnoreAsciiCase("OnModeChanged")
164
0
             || aEvent.EventName.equalsIgnoreAsciiCase("OnTitleChanged"))
165
0
            && !xOwner.is()))
166
0
    {
167
0
        return;
168
0
    }
169
170
0
    impl_updateTitle ();
171
0
}
172
173
void SAL_CALL TitleHelper::frameAction(const css::frame::FrameActionEvent& aEvent)
174
15.7k
{
175
15.7k
    css::uno::Reference< css::frame::XFrame > xOwner;
176
    // SYNCHRONIZED ->
177
15.7k
    {
178
15.7k
        std::unique_lock aLock(m_aMutex);
179
180
15.7k
        xOwner.set(m_xOwner, css::uno::UNO_QUERY);
181
15.7k
    }
182
    // <- SYNCHRONIZED
183
184
15.7k
    if (aEvent.Source != xOwner)
185
0
        return;
186
187
    // we are interested on events only, which must trigger a title bar update
188
    // because component was changed.
189
15.7k
    if (
190
15.7k
        (aEvent.Action == css::frame::FrameAction_COMPONENT_ATTACHED  ) ||
191
11.8k
        (aEvent.Action == css::frame::FrameAction_COMPONENT_REATTACHED) ||
192
11.8k
        (aEvent.Action == css::frame::FrameAction_COMPONENT_DETACHING )
193
15.7k
       )
194
7.87k
    {
195
7.87k
        impl_updateListeningForFrame (xOwner);
196
7.87k
        impl_updateTitle ();
197
7.87k
    }
198
15.7k
}
199
200
void SAL_CALL TitleHelper::disposing(const css::lang::EventObject& aEvent)
201
11.8k
{
202
11.8k
    css::uno::Reference< css::uno::XInterface >         xOwner;
203
11.8k
    css::uno::Reference< css::frame::XUntitledNumbers > xNumbers;
204
11.8k
    ::sal_Int32                                         nLeasedNumber;
205
    // SYNCHRONIZED ->
206
11.8k
    {
207
11.8k
        std::unique_lock aLock(m_aMutex);
208
209
11.8k
        xOwner = m_xOwner;
210
11.8k
        xNumbers = m_xUntitledNumbers;
211
11.8k
        nLeasedNumber = m_nLeasedNumber;
212
11.8k
    }
213
    // <- SYNCHRONIZED
214
215
11.8k
    if ( ! xOwner.is ())
216
0
        return;
217
218
11.8k
    css::uno::Reference< css::frame::XFrame > xFrame(xOwner, css::uno::UNO_QUERY);
219
11.8k
    if (xFrame.is())
220
3.93k
        xFrame->removeFrameActionListener(this);
221
222
11.8k
    if (xOwner != aEvent.Source)
223
0
        return;
224
225
11.8k
    if (
226
11.8k
        (xNumbers.is ()                                                   ) &&
227
7.87k
        (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
228
11.8k
       )
229
7.87k
       xNumbers->releaseNumber (nLeasedNumber);
230
231
    // SYNCHRONIZED ->
232
11.8k
    {
233
11.8k
        std::unique_lock aLock(m_aMutex);
234
235
11.8k
        m_xOwner.clear();
236
11.8k
        m_sTitle.clear();
237
11.8k
        m_nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
238
11.8k
    }
239
    // <- SYNCHRONIZED
240
11.8k
}
241
242
void TitleHelper::impl_sendTitleChangedEvent ()
243
0
{
244
0
    css::uno::Reference<css::uno::XInterface> xOwner;
245
0
    OUString sTitle;
246
    // SYNCHRONIZED ->
247
0
    {
248
0
        std::unique_lock aLock(m_aMutex);
249
250
0
        xOwner = m_xOwner;
251
252
0
        sTitle = m_sTitle;
253
0
    }
254
    // <- SYNCHRONIZED
255
256
0
    css::frame::TitleChangedEvent aEvent(xOwner, sTitle);
257
258
0
    if( ! aEvent.Source.is() )
259
0
        return;
260
261
0
    std::unique_lock aLock(m_aMutex);
262
0
    comphelper::OInterfaceIteratorHelper4 pIt( aLock, m_aTitleChangeListeners );
263
0
    while ( pIt.hasMoreElements() )
264
0
    {
265
0
        aLock.unlock();
266
0
        try
267
0
        {
268
0
            uno::Reference<css::frame::XTitleChangeListener> i = pIt.next();
269
0
            i->titleChanged( aEvent );
270
0
        }
271
0
        catch(const css::uno::Exception&)
272
0
        {
273
0
            aLock.lock();
274
0
            pIt.remove(aLock);
275
0
            aLock.unlock();
276
0
        }
277
0
        aLock.lock();
278
0
    }
279
0
}
280
281
void TitleHelper::impl_updateTitle (bool init)
282
19.6k
{
283
19.6k
    css::uno::Reference<css::uno::XInterface> xOwner;
284
285
    // SYNCHRONIZED ->
286
19.6k
    {
287
19.6k
        std::unique_lock aLock(m_aMutex);
288
289
19.6k
        xOwner = m_xOwner;
290
19.6k
    }
291
    // <- SYNCHRONIZED
292
293
19.6k
    if (css::uno::Reference<css::frame::XModel3> xModel{ xOwner, css::uno::UNO_QUERY })
294
3.93k
    {
295
3.93k
        impl_updateTitleForModel (xModel, init);
296
3.93k
    }
297
15.7k
    else if (css::uno::Reference<css::frame::XController> xController{ xOwner,
298
15.7k
                                                                       css::uno::UNO_QUERY })
299
3.93k
    {
300
3.93k
        impl_updateTitleForController (xController, init);
301
3.93k
    }
302
11.8k
    else if (css::uno::Reference<css::frame::XFrame> xFrame{ xOwner, css::uno::UNO_QUERY })
303
11.8k
    {
304
11.8k
        impl_updateTitleForFrame (xFrame, init);
305
11.8k
    }
306
19.6k
}
307
308
static OUString getURLFromModel(const css::uno::Reference< css::frame::XModel3 >& xModel)
309
3.93k
{
310
3.93k
    if (css::uno::Reference<css::frame::XStorable> xURLProvider{ xModel, css::uno::UNO_QUERY })
311
3.93k
        return xURLProvider->getLocation();
312
0
    return {};
313
3.93k
}
314
315
void TitleHelper::impl_updateTitleForModel (const css::uno::Reference< css::frame::XModel3 >& xModel, bool init)
316
3.93k
{
317
3.93k
    css::uno::Reference< css::uno::XInterface >         xOwner;
318
3.93k
    css::uno::Reference< css::frame::XUntitledNumbers > xNumbers;
319
3.93k
    ::sal_Int32                                         nLeasedNumber;
320
    // SYNCHRONIZED ->
321
3.93k
    {
322
3.93k
        std::unique_lock aLock(m_aMutex);
323
324
        // external title won't be updated internally!
325
        // It has to be set from outside new.
326
3.93k
        if (m_bExternalTitle)
327
0
            return;
328
329
3.93k
        xOwner = m_xOwner;
330
3.93k
        xNumbers = m_xUntitledNumbers;
331
3.93k
        nLeasedNumber = m_nLeasedNumber;
332
3.93k
    }
333
    // <- SYNCHRONIZED
334
335
0
    if (
336
3.93k
        ( ! xOwner.is    ()) ||
337
3.93k
        ( ! xNumbers.is  ()) ||
338
3.93k
        ( ! xModel.is    ())
339
3.93k
       )
340
0
        return;
341
342
3.93k
    OUString sTitle;
343
344
3.93k
    comphelper::SequenceAsHashMap aDescriptor(
345
3.93k
        xModel->getArgs2({ utl::MediaDescriptor::PROP_DOCUMENTTITLE,
346
3.93k
                           utl::MediaDescriptor::PROP_SUGGESTEDSAVEASNAME }));
347
348
3.93k
    if (const OUString sMediaTitle = aDescriptor.getUnpackedValueOrDefault(
349
3.93k
            utl::MediaDescriptor::PROP_DOCUMENTTITLE, OUString());
350
3.93k
        !sMediaTitle.isEmpty())
351
0
    {
352
0
        sTitle = sMediaTitle;
353
0
    }
354
3.93k
    else if (const OUString sURL = getURLFromModel(xModel); !sURL.isEmpty())
355
0
    {
356
0
        sTitle = impl_convertURL2Title(sURL);
357
0
        if (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
358
0
            xNumbers->releaseNumber (nLeasedNumber);
359
0
        nLeasedNumber = css::frame::UntitledNumbersConst::INVALID_NUMBER;
360
0
    }
361
3.93k
    else if (const OUString sSuggestedSaveAsName = aDescriptor.getUnpackedValueOrDefault(
362
3.93k
                 utl::MediaDescriptor::PROP_SUGGESTEDSAVEASNAME, OUString());
363
3.93k
             !sSuggestedSaveAsName.isEmpty())
364
0
    {
365
        // tdf#121537 Use suggested save as name for title if file has not yet been saved
366
0
        sTitle = sSuggestedSaveAsName;
367
0
    }
368
3.93k
    else
369
3.93k
    {
370
3.93k
        if (nLeasedNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
371
3.93k
            nLeasedNumber = xNumbers->leaseNumber (xOwner);
372
373
3.93k
        if (nLeasedNumber != css::frame::UntitledNumbersConst::INVALID_NUMBER)
374
3.93k
            sTitle = xNumbers->getUntitledPrefix() + OUString::number(nLeasedNumber);
375
0
        else
376
0
            sTitle = xNumbers->getUntitledPrefix() + "?";
377
3.93k
    }
378
379
3.93k
    bool     bChanged;
380
    // SYNCHRONIZED ->
381
3.93k
    {
382
3.93k
        std::unique_lock aLock(m_aMutex);
383
384
        // WORKAROUND: the notification is currently sent always,
385
        //             can be changed after shared mode is supported per UNO API
386
3.93k
        bChanged        = !init; // && m_sTitle != sTitle
387
388
3.93k
        m_sTitle        = sTitle;
389
3.93k
        m_nLeasedNumber = nLeasedNumber;
390
3.93k
    }
391
    // <- SYNCHRONIZED
392
393
3.93k
    if (bChanged)
394
0
        impl_sendTitleChangedEvent ();
395
3.93k
}
396
397
void TitleHelper::impl_updateTitleForController (const css::uno::Reference< css::frame::XController >& xController, bool init)
398
3.93k
{
399
3.93k
    css::uno::Reference< css::uno::XInterface >         xOwner;
400
3.93k
    css::uno::Reference< css::frame::XUntitledNumbers > xNumbers;
401
3.93k
    ::sal_Int32                                         nLeasedNumber;
402
    // SYNCHRONIZED ->
403
3.93k
    {
404
3.93k
        std::unique_lock aLock(m_aMutex);
405
406
        // external title won't be updated internally!
407
        // It has to be set from outside new.
408
3.93k
        if (m_bExternalTitle)
409
0
            return;
410
411
3.93k
        xOwner = m_xOwner;
412
3.93k
        xNumbers = m_xUntitledNumbers;
413
3.93k
        nLeasedNumber = m_nLeasedNumber;
414
3.93k
    }
415
    // <- SYNCHRONIZED
416
417
0
    if (
418
3.93k
        ( ! xOwner.is      ()) ||
419
3.93k
        ( ! xNumbers.is    ()) ||
420
3.93k
        ( ! xController.is ())
421
3.93k
       )
422
0
        return;
423
424
3.93k
    OUStringBuffer sTitle(256);
425
426
3.93k
    if (nLeasedNumber == css::frame::UntitledNumbersConst::INVALID_NUMBER)
427
3.93k
        nLeasedNumber = xNumbers->leaseNumber (xOwner);
428
429
3.93k
    css::uno::Reference< css::frame::XTitle > xModelTitle(xController->getModel (), css::uno::UNO_QUERY);
430
3.93k
    css::uno::Reference< css::frame::XModel > xModel = xController->getModel ();
431
3.93k
    if (!xModelTitle.is ())
432
0
        xModelTitle.set(xController, css::uno::UNO_QUERY);
433
3.93k
    if (xModelTitle.is ())
434
3.93k
    {
435
3.93k
        sTitle.append      (xModelTitle->getTitle ());
436
3.93k
        if ( nLeasedNumber > 1 )
437
0
        {
438
0
            sTitle.append(" : " + OUString::number(nLeasedNumber));
439
0
        }
440
3.93k
        if (xModel.is ())
441
3.93k
        {
442
3.93k
            INetURLObject aURL (xModel->getURL ());
443
3.93k
            if (aURL.GetProtocol () != INetProtocol::File
444
3.93k
                && aURL.GetProtocol() != INetProtocol::PrivSoffice
445
3.93k
                && aURL.GetProtocol () != INetProtocol::NotValid)
446
0
            {
447
0
                OUString sRemoteText (FwkResId (STR_REMOTE_TITLE));
448
0
                sTitle.append (sRemoteText);
449
0
            }
450
3.93k
        }
451
3.93k
    }
452
0
    else
453
0
    {
454
0
        sTitle.append (xNumbers->getUntitledPrefix ());
455
0
        if ( nLeasedNumber > 1 )
456
0
        {
457
0
            sTitle.append(nLeasedNumber  );
458
0
        }
459
0
    }
460
461
3.93k
    bool     bChanged;
462
    // SYNCHRONIZED ->
463
3.93k
    {
464
3.93k
        std::unique_lock aLock(m_aMutex);
465
466
3.93k
        OUString sNewTitle       = sTitle.makeStringAndClear ();
467
3.93k
        bChanged        = !init && m_sTitle != sNewTitle;
468
3.93k
        m_sTitle        = sNewTitle;
469
3.93k
        m_nLeasedNumber = nLeasedNumber;
470
3.93k
    }
471
    // <- SYNCHRONIZED
472
473
3.93k
    if (bChanged)
474
0
        impl_sendTitleChangedEvent ();
475
3.93k
}
476
477
void TitleHelper::impl_updateTitleForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame, bool init)
478
11.8k
{
479
11.8k
    if ( ! xFrame.is ())
480
0
        return;
481
482
    // SYNCHRONIZED ->
483
11.8k
    {
484
11.8k
        std::unique_lock aLock(m_aMutex);
485
486
        // external title won't be updated internally!
487
        // It has to be set from outside new.
488
11.8k
        if (m_bExternalTitle)
489
0
            return;
490
11.8k
    }
491
    // <- SYNCHRONIZED
492
493
11.8k
    css::uno::Reference< css::uno::XInterface > xComponent = xFrame->getController ();
494
11.8k
    if ( ! xComponent.is ())
495
0
        xComponent = xFrame->getComponentWindow ();
496
497
11.8k
    OUStringBuffer sTitle (256);
498
499
11.8k
    impl_appendComponentTitle   (sTitle, xComponent);
500
11.8k
#ifndef MACOSX
501
11.8k
    if (!comphelper::IsFuzzing())
502
0
    {
503
        // fdo#70376: We want the window title to contain just the
504
        // document name (from the above "component title").
505
0
        impl_appendProductName      (sTitle);
506
0
        impl_appendModuleName       (sTitle);
507
0
        impl_appendDebugVersion     (sTitle);
508
0
    }
509
11.8k
#endif
510
11.8k
    impl_appendSafeMode         (sTitle);
511
512
11.8k
    bool     bChanged;
513
    // SYNCHRONIZED ->
514
11.8k
    {
515
11.8k
        std::unique_lock aLock(m_aMutex);
516
517
11.8k
        OUString sNewTitle = sTitle.makeStringAndClear ();
518
11.8k
        bChanged  = !init && m_sTitle != sNewTitle;
519
11.8k
        m_sTitle  = sNewTitle;
520
11.8k
    }
521
    // <- SYNCHRONIZED
522
523
11.8k
    if (bChanged)
524
0
        impl_sendTitleChangedEvent ();
525
11.8k
}
526
527
// static
528
void TitleHelper::impl_appendComponentTitle (      OUStringBuffer&                       sTitle    ,
529
                                             const css::uno::Reference< css::uno::XInterface >& xComponent)
530
11.8k
{
531
11.8k
    css::uno::Reference< css::frame::XTitle > xTitle(xComponent, css::uno::UNO_QUERY);
532
533
    // Note: Title has to be used (even if it's empty) if the right interface is supported.
534
11.8k
    if (xTitle.is ())
535
11.8k
        sTitle.append (xTitle->getTitle ());
536
11.8k
}
537
538
// static
539
void TitleHelper::impl_appendProductName (OUStringBuffer& sTitle)
540
0
{
541
0
    OUString name(utl::ConfigManager::getProductName());
542
0
    if (!name.isEmpty())
543
0
    {
544
0
        if (!sTitle.isEmpty())
545
0
        {
546
0
            OUString separator (FwkResId (STR_EMDASH_SEPARATOR));
547
0
            sTitle.append(separator);
548
0
        }
549
0
        sTitle.append(name);
550
0
    }
551
0
}
552
553
void TitleHelper::impl_appendModuleName (OUStringBuffer& sTitle)
554
0
{
555
0
    css::uno::Reference< css::uno::XInterface >        xOwner;
556
0
    css::uno::Reference< css::uno::XComponentContext > xContext;
557
    // SYNCHRONIZED ->
558
0
    {
559
0
        std::unique_lock aLock(m_aMutex);
560
561
0
        xOwner   = m_xOwner;
562
0
        xContext = m_xContext;
563
0
    }
564
    // <- SYNCHRONIZED
565
566
0
    try
567
0
    {
568
0
        css::uno::Reference< css::frame::XModuleManager2 > xModuleManager =
569
0
            css::frame::ModuleManager::create(xContext);
570
571
0
        const OUString                 sID     = xModuleManager->identify(xOwner);
572
0
        ::comphelper::SequenceAsHashMap lProps  = xModuleManager->getByName (sID);
573
0
        const OUString                 sUIName = lProps.getUnpackedValueOrDefault (OFFICEFACTORY_PROPNAME_ASCII_UINAME, OUString());
574
575
        // An UIname property is an optional value !
576
        // So please add it to the title in case it does really exists only.
577
0
        if (!sUIName.isEmpty())
578
0
        {
579
0
            sTitle.append (" "    );
580
0
            sTitle.append      (sUIName);
581
0
        }
582
0
    }
583
0
    catch(const css::uno::Exception&)
584
0
    {}
585
0
}
586
587
#ifdef DBG_UTIL
588
// static
589
void TitleHelper::impl_appendDebugVersion (OUStringBuffer& sTitle)
590
{
591
    OUString version(utl::ConfigManager::getProductVersion());
592
    sTitle.append(' ');
593
    sTitle.append(version);
594
    OUString sVersion = ::utl::Bootstrap::getBuildIdData(u"development"_ustr);
595
    sTitle.append(" [");
596
    sTitle.append(sVersion);
597
    sTitle.append("]");
598
}
599
#else
600
void TitleHelper::impl_appendDebugVersion (OUStringBuffer&)
601
0
{
602
0
}
603
#endif
604
605
// static
606
void TitleHelper::impl_appendSafeMode (OUStringBuffer& sTitle)
607
11.8k
{
608
11.8k
    if (Application::IsSafeModeEnabled())
609
0
        sTitle.append(FwkResId (STR_SAFEMODE_TITLE));
610
11.8k
}
611
612
void TitleHelper::impl_startListeningForModel (const css::uno::Reference< css::frame::XModel >& xModel)
613
3.93k
{
614
3.93k
    css::uno::Reference< css::document::XDocumentEventBroadcaster > xBroadcaster(xModel, css::uno::UNO_QUERY);
615
3.93k
    if ( ! xBroadcaster.is ())
616
0
        return;
617
618
3.93k
    xBroadcaster->addDocumentEventListener (static_cast< css::document::XDocumentEventListener* >(this));
619
3.93k
}
620
621
void TitleHelper::impl_startListeningForController (const css::uno::Reference< css::frame::XController >& xController)
622
3.93k
{
623
3.93k
    xController->addEventListener (static_cast< css::lang::XEventListener* > (static_cast< css::frame::XFrameActionListener* > (this) ) );
624
3.93k
    css::uno::Reference< css::frame::XTitle > xSubTitle(xController->getModel (), css::uno::UNO_QUERY);
625
3.93k
    impl_setSubTitle (xSubTitle);
626
3.93k
}
627
628
void TitleHelper::impl_startListeningForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame)
629
8.22k
{
630
8.22k
    xFrame->addFrameActionListener(this  );
631
8.22k
    impl_updateListeningForFrame  (xFrame);
632
8.22k
}
633
634
void TitleHelper::impl_updateListeningForFrame (const css::uno::Reference< css::frame::XFrame >& xFrame)
635
16.0k
{
636
16.0k
    css::uno::Reference< css::frame::XTitle > xSubTitle(xFrame->getController (), css::uno::UNO_QUERY);
637
16.0k
    impl_setSubTitle (xSubTitle);
638
16.0k
}
639
640
void TitleHelper::impl_setSubTitle (const css::uno::Reference< css::frame::XTitle >& xSubTitle)
641
20.0k
{
642
20.0k
    css::uno::Reference< css::frame::XTitle > xOldSubTitle;
643
    // SYNCHRONIZED ->
644
20.0k
    {
645
20.0k
        std::unique_lock aLock(m_aMutex);
646
647
        // ignore duplicate calls. Makes outside using of this helper more easy :-)
648
20.0k
        xOldSubTitle = m_xSubTitle;
649
20.0k
        if (xOldSubTitle == xSubTitle)
650
12.1k
            return;
651
652
7.87k
        m_xSubTitle = xSubTitle;
653
7.87k
    }
654
    // <- SYNCHRONIZED
655
656
0
    css::uno::Reference< css::frame::XTitleChangeBroadcaster > xOldBroadcaster(xOldSubTitle                                          , css::uno::UNO_QUERY      );
657
7.87k
    css::uno::Reference< css::frame::XTitleChangeBroadcaster > xNewBroadcaster(xSubTitle                                             , css::uno::UNO_QUERY      );
658
7.87k
    css::uno::Reference< css::frame::XTitleChangeListener >    xThis(this);
659
660
7.87k
    if (xOldBroadcaster.is())
661
0
        xOldBroadcaster->removeTitleChangeListener (xThis);
662
663
7.87k
    if (xNewBroadcaster.is())
664
7.87k
        xNewBroadcaster->addTitleChangeListener (xThis);
665
7.87k
}
666
667
// static
668
OUString TitleHelper::impl_convertURL2Title(std::u16string_view sURL)
669
0
{
670
0
    INetURLObject   aURL (sURL);
671
0
    OUString sTitle;
672
673
0
    if (aURL.GetProtocol() == INetProtocol::File)
674
0
    {
675
0
        if (aURL.HasMark())
676
0
            aURL = INetURLObject(aURL.GetURLNoMark());
677
678
0
        sTitle = aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset);
679
0
    }
680
0
    else
681
0
    {
682
0
        if (aURL.hasExtension())
683
0
            sTitle = aURL.getName(INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::WithCharset);
684
685
0
        if ( sTitle.isEmpty() )
686
0
            sTitle = aURL.GetHostPort(INetURLObject::DecodeMechanism::WithCharset);
687
688
0
        if ( sTitle.isEmpty() )
689
0
            sTitle = aURL.GetURLNoPass(INetURLObject::DecodeMechanism::WithCharset);
690
0
    }
691
692
0
    return sTitle;
693
0
}
694
695
} // namespace framework
696
697
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */