Coverage Report

Created: 2026-08-14 10:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/dialog/dinfdlg.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 <svl/eitem.hxx>
21
#include <tools/datetime.hxx>
22
#include <tools/duration.hxx>
23
#include <tools/debug.hxx>
24
#include <tools/urlobj.hxx>
25
#include <utility>
26
#include <vcl/svapp.hxx>
27
#include <vcl/weld/TextView.hxx>
28
#include <vcl/weld/Dialog.hxx>
29
#include <vcl/weld/MessageDialog.hxx>
30
#include <vcl/weld/weldutils.hxx>
31
#include <unotools/datetime.hxx>
32
#include <unotools/localedatawrapper.hxx>
33
#include <unotools/cmdoptions.hxx>
34
#include <comphelper/processfactory.hxx>
35
#include <comphelper/propertyvalue.hxx>
36
#include <comphelper/stl_types.hxx>
37
#include <comphelper/xmlsechelper.hxx>
38
#include <unotools/useroptions.hxx>
39
#include <svtools/ctrlbox.hxx>
40
#include <svtools/imagemgr.hxx>
41
#include <sal/log.hxx>
42
#include <osl/diagnose.h>
43
#include <osl/file.hxx>
44
#include <openuriexternally.hxx>
45
#include <comphelper/lok.hxx>
46
#include <LibreOfficeKit/LibreOfficeKitEnums.h>
47
#include <tools/json_writer.hxx>
48
49
#include <memory>
50
51
#include <comphelper/sequence.hxx>
52
#include <comphelper/string.hxx>
53
#include <com/sun/star/security/DocumentSignatureInformation.hpp>
54
#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
55
#include <unotools/syslocale.hxx>
56
#include <rtl/math.hxx>
57
#include <com/sun/star/beans/PropertyAttribute.hpp>
58
#include <com/sun/star/beans/XPropertyContainer.hpp>
59
#include <com/sun/star/beans/XPropertySet.hpp>
60
#include <com/sun/star/frame/XModel3.hpp>
61
#include <com/sun/star/util/DateTime.hpp>
62
#include <com/sun/star/util/Date.hpp>
63
#include <com/sun/star/util/DateTimeWithTimezone.hpp>
64
#include <com/sun/star/util/DateWithTimezone.hpp>
65
#include <com/sun/star/util/Duration.hpp>
66
#include <com/sun/star/document/XDocumentProperties2.hpp>
67
#include <com/sun/star/document/CmisProperty.hpp>
68
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
69
70
#include <vcl/timer.hxx>
71
#include <vcl/settings.hxx>
72
#include <sfx2/sfxresid.hxx>
73
#include <sfx2/frame.hxx>
74
#include <sfx2/filedlghelper.hxx>
75
#include <sfx2/dinfdlg.hxx>
76
#include <sfx2/sfxsids.hrc>
77
#include <helper.hxx>
78
#include <sfx2/objsh.hxx>
79
#include <sfx2/docfile.hxx>
80
#include <vcl/abstdlg.hxx>
81
#include <sfx2/viewsh.hxx>
82
83
#include <documentfontsdialog.hxx>
84
#include <dinfdlg.hrc>
85
#include <sfx2/strings.hrc>
86
#include <strings.hxx>
87
#include <comphelper/diagnose_ex.hxx>
88
#include "securitypage.hxx"
89
90
#include <algorithm>
91
92
#include <vcl/tabs.hrc>
93
94
using namespace ::com::sun::star;
95
using namespace ::com::sun::star::uno;
96
97
struct CustomProperty
98
{
99
    OUString         m_sName;
100
    css::uno::Any    m_aValue;
101
102
    CustomProperty( OUString sName, css::uno::Any aValue ) :
103
0
        m_sName(std::move( sName )), m_aValue(std::move( aValue )) {}
104
105
    bool operator==(const CustomProperty& rProp) const
106
0
    {
107
0
        return m_sName == rProp.m_sName && m_aValue == rProp.m_aValue;
108
0
    }
109
};
110
111
0
SfxPoolItem* SfxDocumentInfoItem::CreateDefault() { return new SfxDocumentInfoItem; }
112
113
namespace {
114
115
OUString CreateSizeText( sal_Int64 nSize )
116
0
{
117
0
    OUString aUnitStr = " " + SfxResId(STR_BYTES);
118
0
    sal_Int64 nSize1 = nSize;
119
0
    sal_Int64 nSize2 = nSize1;
120
0
    sal_Int64 nMega = 1024 * 1024;
121
0
    sal_Int64 nGiga = nMega * 1024;
122
0
    double fSize = nSize;
123
0
    int nDec = 0;
124
125
0
    if ( nSize1 >= 10000 && nSize1 < nMega )
126
0
    {
127
0
        nSize1 /= 1024;
128
0
        aUnitStr = " " + SfxResId(STR_KB);
129
0
        fSize /= 1024;
130
0
        nDec = 0;
131
0
    }
132
0
    else if ( nSize1 >= nMega && nSize1 < nGiga )
133
0
    {
134
0
        nSize1 /= nMega;
135
0
        aUnitStr = " " + SfxResId(STR_MB);
136
0
        fSize /= nMega;
137
0
        nDec = 2;
138
0
    }
139
0
    else if ( nSize1 >= nGiga )
140
0
    {
141
0
        nSize1 /= nGiga;
142
0
        aUnitStr = " " + SfxResId(STR_GB);
143
0
        fSize /= nGiga;
144
0
        nDec = 3;
145
0
    }
146
0
    const SvtSysLocale aSysLocale;
147
0
    const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
148
0
    OUString aSizeStr = rLocaleWrapper.getNum( nSize1, 0 ) + aUnitStr;
149
0
    if ( nSize1 < nSize2 )
150
0
    {
151
0
        aSizeStr = ::rtl::math::doubleToUString( fSize,
152
0
                rtl_math_StringFormat_F, nDec,
153
0
                rLocaleWrapper.getNumDecimalSep()[0] )
154
0
                 + aUnitStr
155
0
                 + " ("
156
0
                 + rLocaleWrapper.getNum( nSize2, 0 )
157
0
                 + " "
158
0
                 + SfxResId(STR_BYTES)
159
0
                 + ")";
160
0
    }
161
0
    return aSizeStr;
162
0
}
163
164
OUString ConvertDateTime_Impl( std::u16string_view rName,
165
    const util::DateTime& uDT, const LocaleDataWrapper& rWrapper )
166
0
{
167
0
     Date aD(uDT);
168
0
     tools::Time aT(uDT);
169
0
     static constexpr OUString aDelim( u", "_ustr );
170
0
     OUString aStr = rWrapper.getDate( aD )
171
0
                   + aDelim
172
0
                   + rWrapper.getTime( aT );
173
0
     std::u16string_view aAuthor = comphelper::string::stripStart(rName, ' ');
174
0
     if (!aAuthor.empty())
175
0
     {
176
0
        aStr += aDelim + aAuthor;
177
0
     }
178
0
     return aStr;
179
0
}
180
181
}
182
183
184
SfxDocumentInfoItem::SfxDocumentInfoItem()
185
0
    : m_AutoloadDelay(0)
186
0
    , m_isAutoloadEnabled(false)
187
0
    , m_EditingCycles(0)
188
0
    , m_EditingDuration(0)
189
0
    , m_nFileSize(-1)
190
0
    , m_bHasTemplate( true )
191
0
    , m_bDeleteUserData( false )
192
0
    , m_bUseUserData( true )
193
0
    , m_bUseThumbnailSave( true )
194
0
{
195
0
}
196
197
SfxDocumentInfoItem::SfxDocumentInfoItem( const OUString& rFile,
198
        const uno::Reference<document::XDocumentProperties>& i_xDocProps,
199
        const uno::Sequence<document::CmisProperty>& i_cmisProps,
200
        bool bIs, bool _bIs, sal_Int64 _nFileSize )
201
0
    : SfxStringItem( SID_DOCINFO, rFile )
202
0
    , m_AutoloadDelay( i_xDocProps->getAutoloadSecs() )
203
0
    , m_AutoloadURL( i_xDocProps->getAutoloadURL() )
204
0
    , m_isAutoloadEnabled( (m_AutoloadDelay > 0) || !m_AutoloadURL.isEmpty() )
205
0
    , m_DefaultTarget( i_xDocProps->getDefaultTarget() )
206
0
    , m_TemplateName( i_xDocProps->getTemplateName() )
207
0
    , m_Author( i_xDocProps->getAuthor() )
208
0
    , m_CreationDate( i_xDocProps->getCreationDate() )
209
0
    , m_ModifiedBy( i_xDocProps->getModifiedBy() )
210
0
    , m_ModificationDate( i_xDocProps->getModificationDate() )
211
0
    , m_PrintedBy( i_xDocProps->getPrintedBy() )
212
0
    , m_PrintDate( i_xDocProps->getPrintDate() )
213
0
    , m_EditingCycles( i_xDocProps->getEditingCycles() )
214
0
    , m_EditingDuration( i_xDocProps->getEditingDuration() )
215
0
    , m_Description( i_xDocProps->getDescription() )
216
0
    , m_Keywords( ::comphelper::string::convertCommaSeparated(
217
0
                    i_xDocProps->getKeywords()) )
218
0
    , m_Subject( i_xDocProps->getSubject() )
219
0
    , m_Title( i_xDocProps->getTitle() )
220
0
    , m_nFileSize( _nFileSize )
221
0
    , m_bHasTemplate( true )
222
0
    , m_bDeleteUserData( false )
223
0
    , m_bUseUserData( bIs )
224
0
    , m_bUseThumbnailSave( _bIs )
225
0
{
226
0
    Reference< document::XDocumentProperties2 > xDocProps2(i_xDocProps, UNO_QUERY);
227
0
    m_Contributor = ::comphelper::string::convertCommaSeparated(xDocProps2->getContributor());
228
0
    m_Coverage = xDocProps2->getCoverage();
229
0
    m_Identifier = xDocProps2->getIdentifier();
230
0
    m_Publisher = ::comphelper::string::convertCommaSeparated(xDocProps2->getPublisher());
231
0
    m_Relation = ::comphelper::string::convertCommaSeparated(xDocProps2->getRelation());
232
0
    m_Rights = xDocProps2->getRights();
233
0
    m_Source = xDocProps2->getSource();
234
0
    m_Type = xDocProps2->getType();
235
236
0
    try
237
0
    {
238
0
        Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
239
0
        if ( xContainer.is() )
240
0
        {
241
0
            Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
242
0
            const Sequence< beans::Property > lProps = xSet->getPropertySetInfo()->getProperties();
243
0
            for ( const beans::Property& rProp : lProps )
244
0
            {
245
                // "fix" property? => not a custom property => ignore it!
246
0
                if (!(rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE))
247
0
                {
248
0
                    SAL_WARN( "sfx.dialog", "non-removable user-defined property?");
249
0
                    continue;
250
0
                }
251
252
0
                uno::Any aValue = xSet->getPropertyValue(rProp.Name);
253
0
                AddCustomProperty( rProp.Name, aValue );
254
0
            }
255
0
        }
256
257
        // get CMIS properties
258
0
        m_aCmisProperties = i_cmisProps;
259
0
    }
260
0
    catch ( Exception& ) {}
261
0
}
262
263
264
SfxDocumentInfoItem::SfxDocumentInfoItem( const SfxDocumentInfoItem& rItem )
265
0
    : SfxStringItem( rItem )
266
0
    , m_AutoloadDelay( rItem.getAutoloadDelay() )
267
0
    , m_AutoloadURL( rItem.getAutoloadURL() )
268
0
    , m_isAutoloadEnabled( rItem.isAutoloadEnabled() )
269
0
    , m_DefaultTarget( rItem.getDefaultTarget() )
270
0
    , m_TemplateName( rItem.getTemplateName() )
271
0
    , m_Author( rItem.getAuthor() )
272
0
    , m_CreationDate( rItem.getCreationDate() )
273
0
    , m_ModifiedBy( rItem.getModifiedBy() )
274
0
    , m_ModificationDate( rItem.getModificationDate() )
275
0
    , m_PrintedBy( rItem.getPrintedBy() )
276
0
    , m_PrintDate( rItem.getPrintDate() )
277
0
    , m_EditingCycles( rItem.getEditingCycles() )
278
0
    , m_EditingDuration( rItem.getEditingDuration() )
279
0
    , m_Description( rItem.getDescription() )
280
0
    , m_Keywords( rItem.getKeywords() )
281
0
    , m_Contributor(rItem.getContributor())
282
0
    , m_Coverage(rItem.getCoverage())
283
0
    , m_Identifier(rItem.getIdentifier())
284
0
    , m_Publisher(rItem.getPublisher())
285
0
    , m_Relation(rItem.getRelation())
286
0
    , m_Rights(rItem.getRights())
287
0
    , m_Source(rItem.getSource())
288
0
    , m_Type(rItem.getType())
289
0
    , m_Subject( rItem.getSubject() )
290
0
    , m_Title( rItem.getTitle() )
291
0
    , m_nFileSize ( rItem.m_nFileSize )
292
0
    , m_bHasTemplate( rItem.m_bHasTemplate )
293
0
    , m_bDeleteUserData( rItem.m_bDeleteUserData )
294
0
    , m_bUseUserData( rItem.m_bUseUserData )
295
0
    , m_bUseThumbnailSave( rItem.m_bUseThumbnailSave )
296
0
{
297
0
    for (auto const & pOtherProp : rItem.m_aCustomProperties)
298
0
    {
299
0
        AddCustomProperty( pOtherProp->m_sName, pOtherProp->m_aValue );
300
0
    }
301
302
0
    m_aCmisProperties = rItem.m_aCmisProperties;
303
0
}
304
305
SfxDocumentInfoItem::~SfxDocumentInfoItem()
306
0
{
307
0
    ClearCustomProperties();
308
0
}
309
310
SfxDocumentInfoItem* SfxDocumentInfoItem::Clone( SfxItemPool * ) const
311
0
{
312
0
    return new SfxDocumentInfoItem( *this );
313
0
}
314
315
bool SfxDocumentInfoItem::operator==( const SfxPoolItem& rItem) const
316
0
{
317
0
    if (!SfxStringItem::operator==(rItem))
318
0
        return false;
319
0
    const SfxDocumentInfoItem& rInfoItem(static_cast<const SfxDocumentInfoItem&>(rItem));
320
321
0
    return
322
0
         m_AutoloadDelay        == rInfoItem.m_AutoloadDelay     &&
323
0
         m_AutoloadURL          == rInfoItem.m_AutoloadURL       &&
324
0
         m_isAutoloadEnabled    == rInfoItem.m_isAutoloadEnabled &&
325
0
         m_DefaultTarget        == rInfoItem.m_DefaultTarget     &&
326
0
         m_Author               == rInfoItem.m_Author            &&
327
0
         m_CreationDate         == rInfoItem.m_CreationDate      &&
328
0
         m_ModifiedBy           == rInfoItem.m_ModifiedBy        &&
329
0
         m_ModificationDate     == rInfoItem.m_ModificationDate  &&
330
0
         m_PrintedBy            == rInfoItem.m_PrintedBy         &&
331
0
         m_PrintDate            == rInfoItem.m_PrintDate         &&
332
0
         m_EditingCycles        == rInfoItem.m_EditingCycles     &&
333
0
         m_EditingDuration      == rInfoItem.m_EditingDuration   &&
334
0
         m_Description          == rInfoItem.m_Description       &&
335
0
         m_Keywords             == rInfoItem.m_Keywords          &&
336
0
         m_Contributor          == rInfoItem.m_Contributor       &&
337
0
         m_Coverage             == rInfoItem.m_Coverage          &&
338
0
         m_Identifier           == rInfoItem.m_Identifier        &&
339
0
         m_Publisher            == rInfoItem.m_Publisher         &&
340
0
         m_Relation             == rInfoItem.m_Relation          &&
341
0
         m_Rights               == rInfoItem.m_Rights            &&
342
0
         m_Source               == rInfoItem.m_Source            &&
343
0
         m_Type                 == rInfoItem.m_Type              &&
344
0
         m_Subject              == rInfoItem.m_Subject           &&
345
0
         m_Title                == rInfoItem.m_Title             &&
346
0
         comphelper::ContainerUniquePtrEquals(m_aCustomProperties, rInfoItem.m_aCustomProperties) &&
347
0
         m_aCmisProperties.getLength() == rInfoItem.m_aCmisProperties.getLength();
348
0
}
349
350
351
void SfxDocumentInfoItem::resetUserData(const OUString & i_rAuthor)
352
0
{
353
0
    m_Author = i_rAuthor;
354
0
    DateTime now( DateTime::SYSTEM );
355
0
    m_CreationDate = now.GetUNODateTime();
356
0
    m_ModifiedBy = OUString();
357
0
    m_PrintedBy = OUString();
358
0
    m_ModificationDate = util::DateTime();
359
0
    m_PrintDate = util::DateTime();
360
0
    m_EditingDuration = 0;
361
0
    m_EditingCycles = 1;
362
0
}
363
364
365
void SfxDocumentInfoItem::UpdateDocumentInfo(
366
        const uno::Reference<document::XDocumentProperties>& i_xDocProps,
367
        bool i_bDoNotUpdateUserDefined) const
368
0
{
369
0
    if (isAutoloadEnabled()) {
370
0
        i_xDocProps->setAutoloadSecs(getAutoloadDelay());
371
0
        i_xDocProps->setAutoloadURL(getAutoloadURL());
372
0
    } else {
373
0
        i_xDocProps->setAutoloadSecs(0);
374
0
        i_xDocProps->setAutoloadURL(OUString());
375
0
    }
376
0
    i_xDocProps->setDefaultTarget(getDefaultTarget());
377
0
    i_xDocProps->setAuthor(getAuthor());
378
0
    i_xDocProps->setCreationDate(getCreationDate());
379
0
    i_xDocProps->setModifiedBy(getModifiedBy());
380
0
    i_xDocProps->setModificationDate(getModificationDate());
381
0
    i_xDocProps->setPrintedBy(getPrintedBy());
382
0
    i_xDocProps->setPrintDate(getPrintDate());
383
0
    i_xDocProps->setEditingCycles(getEditingCycles());
384
0
    i_xDocProps->setEditingDuration(getEditingDuration());
385
0
    i_xDocProps->setDescription(getDescription());
386
0
    i_xDocProps->setKeywords(
387
0
        ::comphelper::string::convertCommaSeparated(getKeywords()));
388
389
0
    Reference<document::XDocumentProperties2> xDocProps2(i_xDocProps, UNO_QUERY);
390
0
    xDocProps2->setContributor(::comphelper::string::convertCommaSeparated(getContributor()));
391
0
    xDocProps2->setCoverage(getCoverage());
392
0
    xDocProps2->setIdentifier(getIdentifier());
393
0
    xDocProps2->setPublisher(::comphelper::string::convertCommaSeparated(getPublisher()));
394
0
    xDocProps2->setRelation(::comphelper::string::convertCommaSeparated(getRelation()));
395
0
    xDocProps2->setRights(getRights());
396
0
    xDocProps2->setSource(getSource());
397
0
    xDocProps2->setType(getType());
398
0
    xDocProps2->setSubject(getSubject());
399
0
    xDocProps2->setTitle(getTitle());
400
401
    // this is necessary in case of replaying a recorded macro:
402
    // in this case, the macro may contain the 4 old user-defined DocumentInfo
403
    // fields, but not any of the DocumentInfo properties;
404
    // as a consequence, most of the UserDefined properties of the
405
    // DocumentProperties would be summarily deleted here, which does not
406
    // seem like a good idea.
407
0
    if (i_bDoNotUpdateUserDefined)
408
0
        return;
409
410
0
    try
411
0
    {
412
0
        Reference< beans::XPropertyContainer > xContainer = i_xDocProps->getUserDefinedProperties();
413
0
        Reference < beans::XPropertySet > xSet( xContainer, UNO_QUERY );
414
0
        Reference< beans::XPropertySetInfo > xSetInfo = xSet->getPropertySetInfo();
415
0
        const Sequence< beans::Property > lProps = xSetInfo->getProperties();
416
0
        for ( const beans::Property& rProp : lProps )
417
0
        {
418
0
            if (rProp.Attributes & css::beans::PropertyAttribute::REMOVABLE)
419
0
            {
420
0
                xContainer->removeProperty( rProp.Name );
421
0
            }
422
0
        }
423
424
0
        for (auto const & pProp : m_aCustomProperties)
425
0
        {
426
0
            try
427
0
            {
428
0
                xContainer->addProperty( pProp->m_sName,
429
0
                    beans::PropertyAttribute::REMOVABLE, pProp->m_aValue );
430
0
            }
431
0
            catch ( Exception const & )
432
0
            {
433
0
                TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while adding custom properties" );
434
0
            }
435
0
        }
436
0
    }
437
0
    catch ( Exception const & )
438
0
    {
439
0
        TOOLS_WARN_EXCEPTION( "sfx.dialog", "SfxDocumentInfoItem::updateDocumentInfo(): exception while removing custom properties" );
440
0
    }
441
0
}
442
443
444
void SfxDocumentInfoItem::SetDeleteUserData( bool bSet )
445
0
{
446
0
    m_bDeleteUserData = bSet;
447
0
}
448
449
450
void SfxDocumentInfoItem::SetUseUserData( bool bSet )
451
0
{
452
0
    m_bUseUserData = bSet;
453
0
}
454
455
void SfxDocumentInfoItem::SetUseThumbnailSave( bool bSet )
456
0
{
457
0
    m_bUseThumbnailSave = bSet;
458
0
}
459
460
std::vector< std::unique_ptr<CustomProperty> > SfxDocumentInfoItem::GetCustomProperties() const
461
0
{
462
0
    std::vector< std::unique_ptr<CustomProperty> > aRet;
463
0
    for (auto const & pOtherProp : m_aCustomProperties)
464
0
    {
465
0
        std::unique_ptr<CustomProperty> pProp(new CustomProperty( pOtherProp->m_sName,
466
0
                                                    pOtherProp->m_aValue ));
467
0
        aRet.push_back( std::move(pProp) );
468
0
    }
469
470
0
    return aRet;
471
0
}
472
473
void SfxDocumentInfoItem::ClearCustomProperties()
474
0
{
475
0
    m_aCustomProperties.clear();
476
0
}
477
478
void SfxDocumentInfoItem::AddCustomProperty( const OUString& sName, const Any& rValue )
479
0
{
480
0
    std::unique_ptr<CustomProperty> pProp(new CustomProperty( sName, rValue ));
481
0
    m_aCustomProperties.push_back( std::move(pProp) );
482
0
}
483
484
485
void SfxDocumentInfoItem::SetCmisProperties( const Sequence< document::CmisProperty >& cmisProps)
486
0
{
487
0
    m_aCmisProperties = cmisProps;
488
0
}
489
490
bool SfxDocumentInfoItem::QueryValue( Any& rVal, sal_uInt8 nMemberId ) const
491
0
{
492
0
    OUString aValue;
493
0
    sal_Int32 nValue = 0;
494
0
    bool bValue = false;
495
0
    bool bIsInt = false;
496
0
    bool bIsString = false;
497
0
    nMemberId &= ~CONVERT_TWIPS;
498
0
    switch ( nMemberId )
499
0
    {
500
0
        case MID_DOCINFO_USEUSERDATA:
501
0
            bValue = IsUseUserData();
502
0
            break;
503
0
        case MID_DOCINFO_USETHUMBNAILSAVE:
504
0
            bValue = IsUseThumbnailSave();
505
0
            break;
506
0
        case MID_DOCINFO_DELETEUSERDATA:
507
0
            bValue = m_bDeleteUserData;
508
0
            break;
509
0
        case MID_DOCINFO_AUTOLOADENABLED:
510
0
            bValue = isAutoloadEnabled();
511
0
            break;
512
0
        case MID_DOCINFO_AUTOLOADSECS:
513
0
            bIsInt = true;
514
0
            nValue = getAutoloadDelay();
515
0
            break;
516
0
        case MID_DOCINFO_AUTOLOADURL:
517
0
            bIsString = true;
518
0
            aValue = getAutoloadURL();
519
0
            break;
520
0
        case MID_DOCINFO_DEFAULTTARGET:
521
0
            bIsString = true;
522
0
            aValue = getDefaultTarget();
523
0
            break;
524
0
        case MID_DOCINFO_DESCRIPTION:
525
0
            bIsString = true;
526
0
            aValue = getDescription();
527
0
            break;
528
0
        case MID_DOCINFO_KEYWORDS:
529
0
            bIsString = true;
530
0
            aValue = getKeywords();
531
0
            break;
532
0
        case MID_DOCINFO_SUBJECT:
533
0
            bIsString = true;
534
0
            aValue = getSubject();
535
0
            break;
536
0
        case MID_DOCINFO_TITLE:
537
0
            bIsString = true;
538
0
            aValue = getTitle();
539
0
            break;
540
0
        default:
541
0
            OSL_FAIL("Wrong MemberId!");
542
0
            return false;
543
0
     }
544
545
0
    if ( bIsString )
546
0
        rVal <<= aValue;
547
0
    else if ( bIsInt )
548
0
        rVal <<= nValue;
549
0
    else
550
0
        rVal <<= bValue;
551
0
    return true;
552
0
}
553
554
bool SfxDocumentInfoItem::PutValue( const Any& rVal, sal_uInt8 nMemberId )
555
0
{
556
0
    OUString aValue;
557
0
    sal_Int32 nValue=0;
558
0
    bool bValue = false;
559
0
    bool bRet = false;
560
0
    nMemberId &= ~CONVERT_TWIPS;
561
0
    switch ( nMemberId )
562
0
    {
563
0
        case MID_DOCINFO_USEUSERDATA:
564
0
            bRet = (rVal >>= bValue);
565
0
            if ( bRet )
566
0
                SetUseUserData( bValue );
567
0
            break;
568
0
        case MID_DOCINFO_USETHUMBNAILSAVE:
569
0
            bRet = (rVal >>=bValue);
570
0
            if ( bRet )
571
0
                SetUseThumbnailSave( bValue );
572
0
            break;
573
0
        case MID_DOCINFO_DELETEUSERDATA:
574
            // QUESTION: deleting user data was done here; seems to be superfluous!
575
0
            bRet = (rVal >>= bValue);
576
0
            if ( bRet )
577
0
                SetDeleteUserData( bValue );
578
0
            break;
579
0
        case MID_DOCINFO_AUTOLOADENABLED:
580
0
            bRet = (rVal >>= bValue);
581
0
            if ( bRet )
582
0
                m_isAutoloadEnabled = bValue;
583
0
            break;
584
0
        case MID_DOCINFO_AUTOLOADSECS:
585
0
            bRet = (rVal >>= nValue);
586
0
            if ( bRet )
587
0
                m_AutoloadDelay = nValue;
588
0
            break;
589
0
        case MID_DOCINFO_AUTOLOADURL:
590
0
            bRet = (rVal >>= aValue);
591
0
            if ( bRet )
592
0
                m_AutoloadURL = aValue;
593
0
            break;
594
0
        case MID_DOCINFO_DEFAULTTARGET:
595
0
            bRet = (rVal >>= aValue);
596
0
            if ( bRet )
597
0
                m_DefaultTarget = aValue;
598
0
            break;
599
0
        case MID_DOCINFO_DESCRIPTION:
600
0
            bRet = (rVal >>= aValue);
601
0
            if ( bRet )
602
0
                setDescription(aValue);
603
0
            break;
604
0
        case MID_DOCINFO_KEYWORDS:
605
0
            bRet = (rVal >>= aValue);
606
0
            if ( bRet )
607
0
                setKeywords(aValue);
608
0
            break;
609
0
        case MID_DOCINFO_SUBJECT:
610
0
            bRet = (rVal >>= aValue);
611
0
            if ( bRet )
612
0
                setSubject(aValue);
613
0
            break;
614
0
        case MID_DOCINFO_TITLE:
615
0
            bRet = (rVal >>= aValue);
616
0
            if ( bRet )
617
0
                setTitle(aValue);
618
0
            break;
619
0
        default:
620
0
            OSL_FAIL("Wrong MemberId!");
621
0
            return false;
622
0
    }
623
624
0
    return bRet;
625
0
}
626
627
SfxDocumentDescPage::SfxDocumentDescPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
628
0
    : SfxTabPage(pPage, pController, u"sfx/ui/descriptioninfopage.ui"_ustr, u"DescriptionInfoPage"_ustr, &rItemSet)
629
0
    , m_pInfoItem(nullptr)
630
0
    , m_xTitleEd(m_xBuilder->weld_entry(u"title"_ustr))
631
0
    , m_xThemaEd(m_xBuilder->weld_entry(u"subject"_ustr))
632
0
    , m_xKeywordsEd(m_xBuilder->weld_entry(u"keywords"_ustr))
633
0
    , m_xContributorEd(m_xBuilder->weld_entry(u"contributor"_ustr))
634
0
    , m_xCoverageEd(m_xBuilder->weld_entry(u"coverage"_ustr))
635
0
    , m_xIdentifierEd(m_xBuilder->weld_entry(u"identifier"_ustr))
636
0
    , m_xPublisherEd(m_xBuilder->weld_entry(u"publisher"_ustr))
637
0
    , m_xRelationEd(m_xBuilder->weld_entry(u"relation"_ustr))
638
0
    , m_xRightsEd(m_xBuilder->weld_entry(u"rights"_ustr))
639
0
    , m_xSourceEd(m_xBuilder->weld_entry(u"source"_ustr))
640
0
    , m_xTypeEd(m_xBuilder->weld_entry(u"type"_ustr))
641
0
    , m_xCommentEd(m_xBuilder->weld_text_view(u"comments"_ustr))
642
0
{
643
0
    m_xCommentEd->set_size_request(m_xKeywordsEd->get_preferred_size().Width(),
644
0
                                   m_xCommentEd->get_height_rows(16));
645
0
}
646
647
SfxDocumentDescPage::~SfxDocumentDescPage()
648
0
{
649
0
}
650
651
std::unique_ptr<SfxTabPage> SfxDocumentDescPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet *rItemSet)
652
0
{
653
0
     return std::make_unique<SfxDocumentDescPage>(pPage, pController, *rItemSet);
654
0
}
655
656
bool SfxDocumentDescPage::FillItemSet(SfxItemSet *rSet)
657
0
{
658
    // Test whether a change is present
659
0
    const bool bTitleMod = m_xTitleEd->get_value_changed_from_saved();
660
0
    const bool bThemeMod = m_xThemaEd->get_value_changed_from_saved();
661
0
    const bool bKeywordsMod = m_xKeywordsEd->get_value_changed_from_saved();
662
0
    const bool bContributorMod = m_xContributorEd->get_value_changed_from_saved();
663
0
    const bool bCoverageMod = m_xCoverageEd->get_value_changed_from_saved();
664
0
    const bool bIdentifierMod = m_xIdentifierEd->get_value_changed_from_saved();
665
0
    const bool bPublisherMod = m_xPublisherEd->get_value_changed_from_saved();
666
0
    const bool bRelationMod = m_xRelationEd->get_value_changed_from_saved();
667
0
    const bool bRightsMod = m_xRightsEd->get_value_changed_from_saved();
668
0
    const bool bSourceMod = m_xSourceEd->get_value_changed_from_saved();
669
0
    const bool bTypeMod = m_xTypeEd->get_value_changed_from_saved();
670
0
    const bool bCommentMod = m_xCommentEd->get_value_changed_from_saved();
671
0
    if (!(bTitleMod || bThemeMod || bKeywordsMod
672
0
          || bContributorMod || bCoverageMod || bIdentifierMod || bPublisherMod || bRelationMod
673
0
          || bRightsMod || bSourceMod || bTypeMod || bCommentMod))
674
0
    {
675
0
        return false;
676
0
    }
677
678
    // Generating the output data
679
0
    const SfxDocumentInfoItem* pItem = nullptr;
680
0
    SfxDocumentInfoItem* pInfo = nullptr;
681
0
    const SfxItemSet* pExSet = GetDialogExampleSet();
682
683
0
    if ( pExSet && !(pItem = pExSet->GetItemIfSet( SID_DOCINFO )) )
684
0
        pInfo = m_pInfoItem;
685
0
    else if ( pItem )
686
0
        pInfo = new SfxDocumentInfoItem( *pItem );
687
688
0
    if ( !pInfo )
689
0
    {
690
0
        SAL_WARN( "sfx.dialog", "SfxDocumentDescPage::FillItemSet(): no item found" );
691
0
        return false;
692
0
    }
693
694
0
    if ( bTitleMod )
695
0
    {
696
0
        pInfo->setTitle( m_xTitleEd->get_text() );
697
0
    }
698
0
    if ( bThemeMod )
699
0
    {
700
0
        pInfo->setSubject( m_xThemaEd->get_text() );
701
0
    }
702
0
    if ( bKeywordsMod )
703
0
    {
704
0
        pInfo->setKeywords( m_xKeywordsEd->get_text() );
705
0
    }
706
0
    if (bContributorMod)
707
0
    {
708
0
        pInfo->setContributor(m_xContributorEd->get_text());
709
0
    }
710
0
    if (bCoverageMod)
711
0
    {
712
0
        pInfo->setCoverage(m_xCoverageEd->get_text());
713
0
    }
714
0
    if (bIdentifierMod)
715
0
    {
716
0
        pInfo->setIdentifier(m_xIdentifierEd->get_text());
717
0
    }
718
0
    if (bPublisherMod)
719
0
    {
720
0
        pInfo->setPublisher(m_xPublisherEd->get_text());
721
0
    }
722
0
    if (bRelationMod)
723
0
    {
724
0
        pInfo->setRelation(m_xRelationEd->get_text());
725
0
    }
726
0
    if (bRightsMod)
727
0
    {
728
0
        pInfo->setRights(m_xRightsEd->get_text());
729
0
    }
730
0
    if (bSourceMod)
731
0
    {
732
0
        pInfo->setSource(m_xSourceEd->get_text());
733
0
    }
734
0
    if (bTypeMod)
735
0
    {
736
0
        pInfo->setType(m_xTypeEd->get_text());
737
0
    }
738
0
    if ( bCommentMod )
739
0
    {
740
0
        pInfo->setDescription( m_xCommentEd->get_text() );
741
0
    }
742
0
    rSet->Put( *pInfo );
743
    // ptr compare OK, pInfo was created above as temporary data holder
744
0
    if ( !areSfxPoolItemPtrsEqual(pInfo, m_pInfoItem) )
745
0
    {
746
0
        delete pInfo;
747
0
    }
748
749
0
    return true;
750
0
}
751
752
void SfxDocumentDescPage::Reset(const SfxItemSet *rSet)
753
0
{
754
0
    m_pInfoItem = const_cast<SfxDocumentInfoItem*>(&rSet->Get(SID_DOCINFO));
755
756
0
    m_xTitleEd->set_text(m_pInfoItem->getTitle());
757
0
    m_xThemaEd->set_text(m_pInfoItem->getSubject());
758
0
    m_xKeywordsEd->set_text(m_pInfoItem->getKeywords());
759
0
    m_xContributorEd->set_text(m_pInfoItem->getContributor());
760
0
    m_xCoverageEd->set_text(m_pInfoItem->getCoverage());
761
0
    m_xIdentifierEd->set_text(m_pInfoItem->getIdentifier());
762
0
    m_xPublisherEd->set_text(m_pInfoItem->getPublisher());
763
0
    m_xRelationEd->set_text(m_pInfoItem->getRelation());
764
0
    m_xRightsEd->set_text(m_pInfoItem->getRights());
765
0
    m_xSourceEd->set_text(m_pInfoItem->getSource());
766
0
    m_xTypeEd->set_text(m_pInfoItem->getType());
767
0
    m_xCommentEd->set_text(m_pInfoItem->getDescription());
768
769
0
    m_xTitleEd->save_value();
770
0
    m_xThemaEd->save_value();
771
0
    m_xKeywordsEd->save_value();
772
0
    m_xContributorEd->save_value();
773
0
    m_xCoverageEd->save_value();
774
0
    m_xIdentifierEd->save_value();
775
0
    m_xPublisherEd->save_value();
776
0
    m_xRelationEd->save_value();
777
0
    m_xRightsEd->save_value();
778
0
    m_xSourceEd->save_value();
779
0
    m_xTypeEd->save_value();
780
0
    m_xCommentEd->save_value();
781
782
0
    const SfxBoolItem* pROItem = rSet->GetItem(SID_DOC_READONLY, false);
783
0
    if (pROItem && pROItem->GetValue())
784
0
    {
785
0
        m_xTitleEd->set_editable(false);
786
0
        m_xThemaEd->set_editable(false);
787
0
        m_xKeywordsEd->set_editable(false);
788
0
        m_xContributorEd->set_editable(false);
789
0
        m_xCoverageEd->set_editable(false);
790
0
        m_xIdentifierEd->set_editable(false);
791
0
        m_xPublisherEd->set_editable(false);
792
0
        m_xRelationEd->set_editable(false);
793
0
        m_xRightsEd->set_editable(false);
794
0
        m_xSourceEd->set_editable(false);
795
0
        m_xTypeEd->set_editable(false);
796
0
        m_xCommentEd->set_editable(false);
797
0
    }
798
0
}
799
800
SfxDocumentPage::SfxDocumentPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
801
0
    : SfxTabPage(pPage, pController, u"sfx/ui/documentinfopage.ui"_ustr, u"DocumentInfoPage"_ustr, &rItemSet)
802
0
    , bEnableUseUserData( false )
803
0
    , bHandleDelete( false )
804
0
    , m_xBmp(m_xBuilder->weld_image(u"icon"_ustr))
805
0
    , m_xNameED(m_xBuilder->weld_label(u"nameed"_ustr))
806
0
    , m_xChangePassBtn(m_xBuilder->weld_button(u"changepass"_ustr))
807
0
    , m_xShowTypeFT(m_xBuilder->weld_label(u"showtype"_ustr))
808
0
    , m_xFileValEd(m_xBuilder->weld_label(u"showlocation"_ustr))
809
0
    , m_xFileValBtn(m_xBuilder->weld_button(u"btnShowLocation"_ustr))
810
0
    , m_xShowSizeFT(m_xBuilder->weld_label(u"showsize"_ustr))
811
0
    , m_xCreateValFt(m_xBuilder->weld_label(u"showcreate"_ustr))
812
0
    , m_xChangeValFt(m_xBuilder->weld_label(u"showmodify"_ustr))
813
0
    , m_xSignedValFt(m_xBuilder->weld_label(u"showsigned"_ustr))
814
0
    , m_xSignatureBtn(m_xBuilder->weld_button(u"signature"_ustr))
815
0
    , m_xPrintValFt(m_xBuilder->weld_label(u"showprint"_ustr))
816
0
    , m_xTimeLogValFt(m_xBuilder->weld_label(u"showedittime"_ustr))
817
0
    , m_xDocNoValFt(m_xBuilder->weld_label(u"showrevision"_ustr))
818
0
    , m_xUseUserDataCB(m_xBuilder->weld_check_button(u"userdatacb"_ustr))
819
0
    , m_xDeleteBtn(m_xBuilder->weld_button(u"reset"_ustr))
820
0
    , m_xUseThumbnailSaveCB(m_xBuilder->weld_check_button(u"thumbnailsavecb"_ustr))
821
0
    , m_xTemplFt(m_xBuilder->weld_label(u"templateft"_ustr))
822
0
    , m_xTemplValFt(m_xBuilder->weld_label(u"showtemplate"_ustr))
823
0
    , m_xImagePreferredDpiCheckButton(m_xBuilder->weld_check_button(u"image-preferred-dpi-checkbutton"_ustr))
824
0
    , m_xImagePreferredDpiComboBox(m_xBuilder->weld_combo_box(u"image-preferred-dpi-combobox"_ustr))
825
0
{
826
0
    m_xUseUserDataCB->set_accessible_description(SfxResId(STR_A11Y_DESC_USERDATA));
827
828
0
    m_aUnknownSize = m_xShowSizeFT->get_label();
829
0
    m_xShowSizeFT->set_label(OUString());
830
831
0
    m_aMultiSignedStr = m_xSignedValFt->get_label();
832
0
    m_xSignedValFt->set_label(OUString());
833
0
    m_xImagePreferredDpiComboBox->set_entry_width_chars(5); // "width in chars" in Glade not effective
834
835
0
    ImplUpdateSignatures();
836
0
    ImplCheckPasswordState();
837
0
    m_xChangePassBtn->connect_clicked( LINK( this, SfxDocumentPage, ChangePassHdl ) );
838
0
    m_xSignatureBtn->connect_clicked( LINK( this, SfxDocumentPage, SignatureHdl ) );
839
0
    if (comphelper::LibreOfficeKit::isActive())
840
0
        m_xSignatureBtn->hide();
841
0
    m_xDeleteBtn->connect_clicked( LINK( this, SfxDocumentPage, DeleteHdl ) );
842
0
    m_xImagePreferredDpiCheckButton->connect_toggled(LINK(this, SfxDocumentPage, ImagePreferredDPICheckBoxClicked));
843
844
    // [i96288] Check if the document signature command is enabled
845
    // on the main list enable/disable the pushbutton accordingly
846
0
    SvtCommandOptions aCmdOptions;
847
0
    if ( aCmdOptions.LookupDisabled( u"Signature"_ustr ) )
848
0
        m_xSignatureBtn->set_sensitive(false);
849
0
}
850
851
SfxDocumentPage::~SfxDocumentPage()
852
0
{
853
0
    if (m_xPasswordDialog)
854
0
    {
855
0
        m_xPasswordDialog->Response(RET_CANCEL);
856
0
        m_xPasswordDialog.reset();
857
0
    }
858
0
}
859
860
IMPL_LINK_NOARG(SfxDocumentPage, FileValHdl, weld::Button&, void)
861
0
{
862
0
    sfx2::openUriExternally(m_sFileURL, false, GetFrameWeld());
863
0
}
864
865
IMPL_LINK_NOARG(SfxDocumentPage, DeleteHdl, weld::Button&, void)
866
0
{
867
0
    OUString aName;
868
0
    if (bEnableUseUserData && m_xUseUserDataCB->get_active())
869
0
        aName = SvtUserOptions().GetFullName();
870
0
    const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
871
0
    DateTime now( DateTime::SYSTEM );
872
0
    util::DateTime uDT( now.GetUNODateTime() );
873
0
    m_xCreateValFt->set_label( ConvertDateTime_Impl( aName, uDT, rLocaleWrapper ) );
874
0
    m_xChangeValFt->set_label( u""_ustr );
875
0
    m_xPrintValFt->set_label( u""_ustr );
876
0
    m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( tools::Duration() ) );
877
0
    m_xDocNoValFt->set_label(OUString('1'));
878
0
    bHandleDelete = true;
879
0
}
880
881
IMPL_LINK_NOARG(SfxDocumentPage, SignatureHdl, weld::Button&, void)
882
0
{
883
0
    SfxObjectShell* pDoc = SfxObjectShell::Current();
884
0
    if( pDoc )
885
0
    {
886
0
        pDoc->SignDocumentContent(GetFrameWeld(), [this] (bool /*bHaveWeSigned*/) {
887
0
            ImplUpdateSignatures();
888
0
        });
889
0
    }
890
0
}
891
892
IMPL_LINK_NOARG(SfxDocumentPage, ImagePreferredDPICheckBoxClicked, weld::Toggleable&, void)
893
0
{
894
0
    bool bEnabled = m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE;
895
0
    m_xImagePreferredDpiComboBox->set_sensitive(bEnabled);
896
0
}
897
898
IMPL_LINK_NOARG(SfxDocumentPage, ChangePassHdl, weld::Button&, void)
899
0
{
900
0
    SfxObjectShell* pShell = SfxObjectShell::Current();
901
0
    do
902
0
    {
903
0
        if (!pShell)
904
0
            break;
905
0
        SfxItemSet& rMedSet = pShell->GetMedium()->GetItemSet();
906
0
        std::shared_ptr<const SfxFilter> pFilter = pShell->GetMedium()->GetFilter();
907
0
        if (!pFilter)
908
0
            break;
909
0
        if (comphelper::LibreOfficeKit::isActive())
910
0
        {
911
            // MS Types support max len of 15 characters while OOXML is "unlimited"
912
0
            const sal_uInt16 maxPwdLen = sfx2::IsMSType(pFilter) && !sfx2::IsOOXML(pFilter) ? 15 : 0;
913
            // handle the pwd dialog asynchronously
914
0
            VclAbstractDialogFactory * pFact = VclAbstractDialogFactory::Create();
915
0
            m_xPasswordDialog = pFact->CreatePasswordToOpenModifyDialog(GetFrameWeld(), maxPwdLen, false);
916
0
            m_xPasswordDialog->AllowEmpty(); // needed to remove password
917
0
            m_xPasswordDialog->StartExecuteAsync([this, pFilter=std::move(pFilter), &rMedSet, pShell](sal_Int32 nResult)
918
0
            {
919
0
                if (nResult == RET_OK)
920
0
                {
921
0
                    sfx2::SetPassword(pFilter, &rMedSet, m_xPasswordDialog->GetPasswordToOpen(),
922
0
                                      m_xPasswordDialog->GetPasswordToOpen(), true);
923
0
                    tools::JsonWriter payloadJson;
924
0
                    payloadJson.put("password", m_xPasswordDialog->GetPasswordToOpen());
925
0
                    payloadJson.put("isToModify", false);
926
927
0
                    SfxViewShell *pViewShell = SfxViewShell::Current();
928
0
                    if (pViewShell)
929
0
                        pViewShell->libreOfficeKitViewCallback(LOK_CALLBACK_DOCUMENT_PASSWORD_RESET, payloadJson.finishAndGetAsOString());
930
931
0
                    pShell->SetModified();
932
0
                }
933
0
                m_xPasswordDialog->disposeOnce();
934
0
            });
935
0
        } else {
936
0
            sfx2::RequestPassword(pFilter, OUString(), &rMedSet, GetFrameWeld()->GetXWindow());
937
0
            pShell->SetModified();
938
0
        }
939
0
    }
940
0
    while (false);
941
0
}
942
943
void SfxDocumentPage::ImplUpdateSignatures()
944
0
{
945
0
    SfxObjectShell* pDoc = SfxObjectShell::Current();
946
0
    if ( !pDoc )
947
0
        return;
948
949
0
    SfxMedium* pMedium = pDoc->GetMedium();
950
0
    if ( !pMedium || pMedium->GetName().isEmpty() || !pMedium->GetStorage().is() )
951
0
        return;
952
953
0
    Reference< security::XDocumentDigitalSignatures > xD;
954
0
    try
955
0
    {
956
0
        xD = security::DocumentDigitalSignatures::createDefault(comphelper::getProcessComponentContext());
957
0
        xD->setParentWindow(GetDialogController()->getDialog()->GetXWindow());
958
0
    }
959
0
    catch ( const css::uno::DeploymentException& )
960
0
    {
961
0
    }
962
0
    OUString s;
963
0
    Sequence< security::DocumentSignatureInformation > aInfos;
964
965
0
    if ( xD.is() )
966
0
        aInfos = xD->verifyDocumentContentSignatures( pMedium->GetZipStorageToSign_Impl(),
967
0
                                                      uno::Reference< io::XInputStream >() );
968
0
    if ( aInfos.getLength() > 1 )
969
0
        s = m_aMultiSignedStr;
970
0
    else if ( aInfos.getLength() == 1 )
971
0
    {
972
0
        const security::DocumentSignatureInformation& rInfo = aInfos[ 0 ];
973
0
        s = utl::GetDateTimeString( rInfo.SignatureDate, rInfo.SignatureTime ) + ", " +
974
0
            comphelper::xmlsec::GetContentPart(rInfo.Signer->getSubjectName(), rInfo.Signer->getCertificateKind());
975
0
    }
976
0
    m_xSignedValFt->set_label(s);
977
0
}
978
979
void SfxDocumentPage::ImplCheckPasswordState()
980
0
{
981
0
    SfxObjectShell* pShell = SfxObjectShell::Current();
982
0
    do
983
0
    {
984
0
        if (!pShell)
985
0
            break;
986
0
        const SfxUnoAnyItem* pEncryptionDataItem = pShell->GetMedium()->GetItemSet().GetItem(SID_ENCRYPTIONDATA, false);
987
0
        uno::Sequence< beans::NamedValue > aEncryptionData;
988
0
        if (pEncryptionDataItem)
989
0
            pEncryptionDataItem->GetValue() >>= aEncryptionData;
990
0
        else
991
0
             break;
992
993
0
        if (!aEncryptionData.hasElements())
994
0
             break;
995
0
        m_xChangePassBtn->set_sensitive(true);
996
0
        return;
997
0
    }
998
0
    while (false);
999
0
    m_xChangePassBtn->set_sensitive(comphelper::LibreOfficeKit::isActive());
1000
0
}
1001
1002
std::unique_ptr<SfxTabPage> SfxDocumentPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
1003
0
{
1004
0
     return std::make_unique<SfxDocumentPage>(pPage, pController, *rItemSet);
1005
0
}
1006
1007
void SfxDocumentPage::EnableUseUserData()
1008
0
{
1009
0
    bEnableUseUserData = true;
1010
0
    m_xUseUserDataCB->show();
1011
0
    m_xDeleteBtn->show();
1012
0
}
1013
1014
bool SfxDocumentPage::FillItemSet( SfxItemSet* rSet )
1015
0
{
1016
0
    bool bRet = false;
1017
1018
0
    if ( !bHandleDelete && bEnableUseUserData &&
1019
0
         m_xUseUserDataCB->get_state_changed_from_saved() )
1020
0
    {
1021
0
        const SfxItemSet* pExpSet = GetDialogExampleSet();
1022
0
        const SfxDocumentInfoItem* pInfoItem;
1023
1024
0
        if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO ) ) )
1025
0
        {
1026
0
            bool bUseData = ( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1027
0
            const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( bUseData );
1028
0
            rSet->Put( *pInfoItem );
1029
0
            bRet = true;
1030
0
        }
1031
0
    }
1032
1033
    // tdf#116833 - don't overwrite deletion of document information
1034
0
    if (m_xUseThumbnailSaveCB->get_state_changed_from_saved())
1035
0
    {
1036
0
        const SfxItemSet* pExpSet = GetDialogExampleSet();
1037
0
        const SfxDocumentInfoItem* pInfoItem;
1038
1039
0
        if (pExpSet && (pInfoItem = pExpSet->GetItemIfSet(SID_DOCINFO)))
1040
0
        {
1041
0
            bool bUseThumbnail = (TRISTATE_TRUE == m_xUseThumbnailSaveCB->get_state());
1042
0
            const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseThumbnailSave(bUseThumbnail);
1043
0
            rSet->Put(*pInfoItem);
1044
0
            bRet = true;
1045
0
        }
1046
0
    }
1047
1048
0
    if ( bHandleDelete )
1049
0
    {
1050
0
        const SfxItemSet* pExpSet = GetDialogExampleSet();
1051
0
        const SfxDocumentInfoItem* pInfoItem;
1052
0
        if ( pExpSet && (pInfoItem = pExpSet->GetItemIfSet( SID_DOCINFO )) )
1053
0
        {
1054
0
            bool bUseAuthor = bEnableUseUserData && m_xUseUserDataCB->get_active();
1055
0
            SfxDocumentInfoItem newItem( *pInfoItem );
1056
0
            newItem.resetUserData( bUseAuthor
1057
0
                ? SvtUserOptions().GetFullName()
1058
0
                : OUString() );
1059
0
            const_cast<SfxDocumentInfoItem*>(pInfoItem)->SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1060
0
            newItem.SetUseUserData( TRISTATE_TRUE == m_xUseUserDataCB->get_state() );
1061
1062
0
            newItem.SetDeleteUserData( true );
1063
0
            rSet->Put( newItem );
1064
0
            bRet = true;
1065
0
        }
1066
0
    }
1067
1068
0
    SfxObjectShell* pDocSh = SfxObjectShell::Current();
1069
0
    if (pDocSh)
1070
0
    {
1071
0
        uno::Reference<lang::XMultiServiceFactory> xFac(pDocSh->GetModel(), uno::UNO_QUERY);
1072
0
        if (xFac.is())
1073
0
        {
1074
0
            uno::Reference<beans::XPropertySet> xProps(xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY);
1075
0
            if (xProps.is())
1076
0
            {
1077
0
                sal_Int32 nImagePreferredDPI = 0;
1078
0
                if (m_xImagePreferredDpiCheckButton->get_state() == TRISTATE_TRUE)
1079
0
                {
1080
0
                    OUString aImagePreferredDPIString = m_xImagePreferredDpiComboBox->get_active_text();
1081
0
                    nImagePreferredDPI = aImagePreferredDPIString.toInt32();
1082
0
                }
1083
0
                xProps->setPropertyValue(u"ImagePreferredDPI"_ustr, uno::Any(nImagePreferredDPI));
1084
0
            }
1085
0
        }
1086
0
    }
1087
1088
0
    return bRet;
1089
0
}
1090
1091
void SfxDocumentPage::Reset( const SfxItemSet* rSet )
1092
0
{
1093
    // Determine the document information
1094
0
    const SfxDocumentInfoItem& rInfoItem = rSet->Get(SID_DOCINFO);
1095
1096
    // template data
1097
0
    if (rInfoItem.HasTemplate())
1098
0
    {
1099
0
        const OUString& rName = rInfoItem.getTemplateName();
1100
0
        if (rName.getLength() > SAL_MAX_INT16) // tdf#122780 pick some ~arbitrary max size
1101
0
            m_xTemplValFt->set_label(rName.copy(0, SAL_MAX_INT16));
1102
0
        else
1103
0
            m_xTemplValFt->set_label(rName);
1104
0
    }
1105
0
    else
1106
0
    {
1107
0
        m_xTemplFt->hide();
1108
0
        m_xTemplValFt->hide();
1109
0
    }
1110
1111
    // determine file name
1112
0
    OUString aFile( rInfoItem.GetValue() );
1113
0
    OUString aFactory( aFile );
1114
0
    if ( aFile.getLength() > 2 && aFile[0] == '[' )
1115
0
    {
1116
0
        sal_Int32 nPos = aFile.indexOf( ']' );
1117
0
        aFactory = aFile.copy( 1, nPos-1  );
1118
0
        aFile = aFile.copy( nPos+1 );
1119
0
    }
1120
1121
    // determine name
1122
0
    INetURLObject aURL(aFile);
1123
0
    OUString aName = aURL.GetLastName(INetURLObject::DecodeMechanism::WithCharset);
1124
0
    if ( aName.isEmpty() || aURL.GetProtocol() == INetProtocol::PrivSoffice )
1125
0
        aName = SfxResId( STR_NONAME );
1126
0
    m_xNameED->set_label( aName );
1127
1128
    // determine context symbol
1129
0
    aURL.SetSmartProtocol( INetProtocol::File );
1130
0
    aURL.SetSmartURL( aFactory);
1131
0
    const OUString aMainURL = aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE );
1132
0
    OUString aImage = SvFileInformationManager::GetImageId( aURL, true );
1133
0
    m_xBmp->set_from_icon_name(aImage);
1134
1135
    // determine size and type
1136
0
    OUString aSizeText( m_aUnknownSize );
1137
    // we might already know the size as an optional argument passed to .uno:SetDocumentProperties
1138
0
    sal_Int64 nSize = rInfoItem.getFileSize();
1139
    // otherwise, for some protocols we can reliably query for it
1140
0
    if (nSize == -1 && (aURL.GetProtocol() == INetProtocol::File || aURL.isAnyKnownWebDAVScheme()))
1141
0
        nSize = SfxContentHelper::GetSize( aURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ) );
1142
0
    if (nSize != -1)
1143
0
        aSizeText = CreateSizeText( nSize );
1144
0
    m_xShowSizeFT->set_label( aSizeText );
1145
1146
0
    OUString aDescription = SvFileInformationManager::GetDescription( INetURLObject(aMainURL) );
1147
0
    if ( aDescription.isEmpty() )
1148
0
        aDescription = SfxResId( STR_SFX_NEWOFFICEDOC );
1149
0
    m_xShowTypeFT->set_label( aDescription );
1150
1151
0
    m_sFileURL.clear();
1152
    // determine location
1153
    // online we don't know file location so we just set it as the name
1154
0
    if (comphelper::LibreOfficeKit::isActive())
1155
0
    {
1156
0
        m_xFileValEd->set_label(aName);
1157
0
        m_sFileURL = aName;
1158
1159
        // Disable setting/changing password on text files.
1160
        // Perhaps this needs to be done for both Online and Desktop.
1161
0
        OUString sExtension(INetURLObject(aMainURL).getExtension());
1162
0
        if (!sExtension.isEmpty())
1163
0
        {
1164
0
            sExtension = sExtension.toAsciiLowerCase();
1165
0
            if (sExtension == "txt" || sExtension == "csv")
1166
0
                m_xChangePassBtn->set_sensitive(false);
1167
0
        }
1168
0
    }
1169
0
    else
1170
0
    {
1171
0
        aURL.SetSmartURL( aFile);
1172
0
        if ( aURL.GetProtocol() == INetProtocol::File )
1173
0
        {
1174
0
            INetURLObject aPath(std::move(aURL));
1175
0
            aPath.setFinalSlash();
1176
0
            aPath.removeSegment();
1177
            // we know it's a folder -> don't need the final slash, but it's better for WB_PATHELLIPSIS
1178
0
            aPath.removeFinalSlash();
1179
0
            OUString aText( aPath.PathToFileName() ); //! (pb) MaxLen?
1180
0
            m_xFileValEd->set_label(aText);
1181
0
            OUString aURLStr;
1182
0
            osl::FileBase::getFileURLFromSystemPath(aText, aURLStr);
1183
0
            m_sFileURL = aURLStr;
1184
0
        }
1185
0
        else if (aURL.GetProtocol() != INetProtocol::PrivSoffice)
1186
0
        {
1187
0
            m_xFileValEd->set_label(aURL.GetPartBeforeLastName());
1188
0
            m_sFileURL = m_xFileValEd->get_label();
1189
0
        }
1190
0
    }
1191
0
    m_xFileValBtn->connect_clicked( LINK( this, SfxDocumentPage, FileValHdl ) );
1192
0
    if (m_sFileURL.isEmpty())
1193
0
        m_xFileValBtn->set_sensitive(false);
1194
1195
    // handle access data
1196
0
    bool bUseUserData = rInfoItem.IsUseUserData();
1197
0
    const LocaleDataWrapper& rLocaleWrapper( Application::GetSettings().GetLocaleDataWrapper() );
1198
0
    m_xCreateValFt->set_label( ConvertDateTime_Impl( rInfoItem.getAuthor(),
1199
0
        rInfoItem.getCreationDate(), rLocaleWrapper ) );
1200
0
    util::DateTime aTime( rInfoItem.getModificationDate() );
1201
0
    if ( aTime.Month > 0 )
1202
0
        m_xChangeValFt->set_label( ConvertDateTime_Impl(
1203
0
            rInfoItem.getModifiedBy(), aTime, rLocaleWrapper ) );
1204
0
    aTime = rInfoItem.getPrintDate();
1205
0
    if ( aTime.Month > 0 )
1206
0
        m_xPrintValFt->set_label( ConvertDateTime_Impl( rInfoItem.getPrintedBy(),
1207
0
            aTime, rLocaleWrapper ) );
1208
0
    const tools::Long nTime = rInfoItem.getEditingDuration();
1209
0
    if ( bUseUserData )
1210
0
    {
1211
0
        assert(SAL_MIN_INT32 <= nTime/86400 && nTime/86400 <= SAL_MAX_INT32);
1212
0
        const tools::Duration aD( static_cast<sal_Int32>(nTime)/86400,
1213
0
                (nTime%86400)/3600, (nTime%3600)/60, nTime%60, 0);
1214
0
        m_xTimeLogValFt->set_label( rLocaleWrapper.getDuration( aD ) );
1215
0
        m_xDocNoValFt->set_label( OUString::number(
1216
0
            rInfoItem.getEditingCycles() ) );
1217
0
    }
1218
1219
0
    bool bUseThumbnailSave = rInfoItem.IsUseThumbnailSave();
1220
1221
    // Check for cmis properties where otherwise unavailable
1222
0
    if ( rInfoItem.isCmisDocument( ) )
1223
0
    {
1224
0
        const uno::Sequence< document::CmisProperty >& aCmisProps = rInfoItem.GetCmisProperties();
1225
0
        for ( const auto& rCmisProp : aCmisProps )
1226
0
        {
1227
0
            if ( rCmisProp.Id == "cmis:contentStreamLength" &&
1228
0
                 aSizeText == m_aUnknownSize )
1229
0
            {
1230
0
                Sequence< sal_Int64 > seqValue;
1231
0
                rCmisProp.Value >>= seqValue;
1232
0
                SvNumberFormatter aNumberFormatter( ::comphelper::getProcessComponentContext(),
1233
0
                        Application::GetSettings().GetLanguageTag().getLanguageType() );
1234
0
                sal_uInt32 nIndex = aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
1235
0
                if ( seqValue.hasElements() )
1236
0
                {
1237
0
                    OUString sValue = aNumberFormatter.GetInputLineString( seqValue[0], nIndex );
1238
0
                    m_xShowSizeFT->set_label( CreateSizeText( sValue.toInt64( ) ) );
1239
0
                }
1240
0
            }
1241
1242
0
            util::DateTime uDT;
1243
0
            OUString emptyDate = ConvertDateTime_Impl( u"", uDT, rLocaleWrapper );
1244
0
            if ( rCmisProp.Id == "cmis:creationDate" &&
1245
0
                 (m_xCreateValFt->get_label() == emptyDate ||
1246
0
                  m_xCreateValFt->get_label().isEmpty()))
1247
0
            {
1248
0
                Sequence< util::DateTime > seqValue;
1249
0
                rCmisProp.Value >>= seqValue;
1250
0
                if ( seqValue.hasElements() )
1251
0
                {
1252
0
                    m_xCreateValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1253
0
                }
1254
0
            }
1255
0
            if ( rCmisProp.Id == "cmis:lastModificationDate" &&
1256
0
                 (m_xChangeValFt->get_label() == emptyDate ||
1257
0
                  m_xChangeValFt->get_label().isEmpty()))
1258
0
            {
1259
0
                Sequence< util::DateTime > seqValue;
1260
0
                rCmisProp.Value >>= seqValue;
1261
0
                if ( seqValue.hasElements() )
1262
0
                {
1263
0
                    m_xChangeValFt->set_label( ConvertDateTime_Impl( u"", seqValue[0], rLocaleWrapper ) );
1264
0
                }
1265
0
            }
1266
0
        }
1267
0
    }
1268
1269
0
    m_xUseUserDataCB->set_active(bUseUserData);
1270
0
    m_xUseUserDataCB->save_state();
1271
0
    m_xUseUserDataCB->set_sensitive( bEnableUseUserData );
1272
0
    bHandleDelete = false;
1273
0
    m_xDeleteBtn->set_sensitive( bEnableUseUserData );
1274
0
    m_xUseThumbnailSaveCB->set_active(bUseThumbnailSave);
1275
0
    m_xUseThumbnailSaveCB->save_state();
1276
1277
0
    SfxObjectShell* pDocSh = SfxObjectShell::Current();
1278
0
    sal_Int32 nImagePreferredDPI = 0;
1279
0
    if (pDocSh)
1280
0
    {
1281
0
        try
1282
0
        {
1283
0
            uno::Reference< lang::XMultiServiceFactory > xFac( pDocSh->GetModel(), uno::UNO_QUERY );
1284
0
            if (xFac)
1285
0
            {
1286
0
                uno::Reference< beans::XPropertySet > xProps( xFac->createInstance(u"com.sun.star.document.Settings"_ustr), uno::UNO_QUERY );
1287
0
                if (xProps)
1288
0
                    xProps->getPropertyValue(u"ImagePreferredDPI"_ustr) >>= nImagePreferredDPI;
1289
0
            }
1290
0
        }
1291
0
        catch( uno::Exception& )
1292
0
        {
1293
0
        }
1294
0
    }
1295
0
    if (nImagePreferredDPI > 0)
1296
0
    {
1297
0
        m_xImagePreferredDpiCheckButton->set_state(TRISTATE_TRUE);
1298
0
        m_xImagePreferredDpiComboBox->set_sensitive(true);
1299
0
        m_xImagePreferredDpiComboBox->set_entry_text(OUString::number(nImagePreferredDPI));
1300
0
    }
1301
0
    else
1302
0
    {
1303
0
        m_xImagePreferredDpiCheckButton->set_state(TRISTATE_FALSE);
1304
0
        m_xImagePreferredDpiComboBox->set_sensitive(false);
1305
0
        m_xImagePreferredDpiComboBox->set_entry_text(u""_ustr);
1306
0
    }
1307
1308
0
}
1309
1310
SfxDocumentInfoDialog::SfxDocumentInfoDialog(weld::Window* pParent, const SfxItemSet& rItemSet)
1311
0
    : SfxTabDialogController(pParent, u"sfx/ui/documentpropertiesdialog.ui"_ustr,
1312
0
                             u"DocumentPropertiesDialog"_ustr, &rItemSet)
1313
0
{
1314
0
    const SfxDocumentInfoItem& rInfoItem = rItemSet.Get( SID_DOCINFO );
1315
1316
#ifdef DBG_UTIL
1317
    const SfxStringItem* pURLItem = rItemSet.GetItem<SfxStringItem>(SID_BASEURL, false);
1318
    DBG_ASSERT( pURLItem, "No BaseURL provided for InternetTabPage!" );
1319
#endif
1320
1321
     // Determine the Titles
1322
0
    OUString aTitle(m_xDialog->get_title());
1323
0
    const SfxStringItem* pItem = rItemSet.GetItemIfSet( SID_EXPLORER_PROPS_START, false );
1324
0
    if ( !pItem )
1325
0
    {
1326
        // File name
1327
0
        const OUString& aFile( rInfoItem.GetValue() );
1328
1329
0
        INetURLObject aURL;
1330
0
        aURL.SetSmartProtocol( INetProtocol::File );
1331
0
        aURL.SetSmartURL( aFile);
1332
0
        if ( INetProtocol::PrivSoffice != aURL.GetProtocol() )
1333
0
        {
1334
0
            OUString aLastName( aURL.GetLastName() );
1335
0
            if ( !aLastName.isEmpty() )
1336
0
                aTitle = aTitle.replaceFirst("%1", aLastName);
1337
0
            else
1338
0
                aTitle = aTitle.replaceFirst("%1", aFile);
1339
0
        }
1340
0
        else
1341
0
            aTitle = aTitle.replaceFirst("%1", SfxResId( STR_NONAME ));
1342
0
    }
1343
0
    else
1344
0
    {
1345
0
        aTitle = aTitle.replaceFirst("%1", pItem->GetValue());
1346
0
    }
1347
0
    m_xDialog->set_title(aTitle);
1348
1349
    // Property Pages
1350
0
    AddTabPage(u"general"_ustr, TabResId(RID_TAB_ORGANIZER.aLabel), SfxDocumentPage::Create,
1351
0
               RID_L + RID_TAB_ORGANIZER.sIconName);
1352
0
    AddTabPage(u"description"_ustr, TabResId(RID_TAB_DESCRIPTION.aLabel), SfxDocumentDescPage::Create,
1353
0
               RID_L + RID_TAB_DESCRIPTION.sIconName);
1354
1355
0
    AddTabPage(u"customprops"_ustr, TabResId(RID_TAB_CUSTOM.aLabel),
1356
0
               SfxCustomPropertiesPage::Create, RID_L + RID_TAB_CUSTOM.sIconName);
1357
1358
0
    if (rInfoItem.isCmisDocument())
1359
0
        AddTabPage(u"cmisprops"_ustr, TabResId(RID_TAB_CMIS.aLabel),
1360
0
                   SfxCmisPropertiesPage::Create, RID_L + RID_TAB_CMIS.sIconName);
1361
    // Disable security page for online as not fully asynced yet
1362
0
    if (!comphelper::LibreOfficeKit::isActive())
1363
0
        AddTabPage(u"security"_ustr, TabResId(RID_TAB_SECURITY.aLabel), SfxSecurityPage::Create,
1364
0
                   RID_L + RID_TAB_SECURITY.sIconName);
1365
0
}
1366
1367
void SfxDocumentInfoDialog::PageCreated(const OUString& rId, SfxTabPage &rPage)
1368
0
{
1369
0
    if (rId == "general")
1370
0
        static_cast<SfxDocumentPage&>(rPage).EnableUseUserData();
1371
0
}
1372
1373
void SfxDocumentInfoDialog::AddFontTabPage()
1374
0
{
1375
0
    AddTabPage(u"font"_ustr, TabResId(RID_TAB_FONT.aLabel),
1376
0
               SfxDocumentFontsPage::Create, RID_L + RID_TAB_FONT.sIconName);
1377
0
}
1378
1379
// class CustomPropertiesYesNoButton -------------------------------------
1380
1381
CustomPropertiesYesNoButton::CustomPropertiesYesNoButton(std::unique_ptr<weld::Widget> xTopLevel,
1382
                                                         std::unique_ptr<weld::RadioButton> xYesButton,
1383
                                                         std::unique_ptr<weld::RadioButton> xNoButton)
1384
0
    : m_xTopLevel(std::move(xTopLevel))
1385
0
    , m_xYesButton(std::move(xYesButton))
1386
0
    , m_xNoButton(std::move(xNoButton))
1387
0
{
1388
0
    CheckNo();
1389
0
}
1390
1391
CustomPropertiesYesNoButton::~CustomPropertiesYesNoButton()
1392
0
{
1393
0
}
1394
1395
1396
DurationDialog_Impl::DurationDialog_Impl(weld::Widget* pParent, const util::Duration& rDuration)
1397
0
    : GenericDialogController(pParent, u"sfx/ui/editdurationdialog.ui"_ustr, u"EditDurationDialog"_ustr)
1398
0
    , m_xNegativeCB(m_xBuilder->weld_check_button(u"negative"_ustr))
1399
0
    , m_xYearNF(m_xBuilder->weld_spin_button(u"years"_ustr))
1400
0
    , m_xMonthNF(m_xBuilder->weld_spin_button(u"months"_ustr))
1401
0
    , m_xDayNF(m_xBuilder->weld_spin_button(u"days"_ustr))
1402
0
    , m_xHourNF(m_xBuilder->weld_spin_button(u"hours"_ustr))
1403
0
    , m_xMinuteNF(m_xBuilder->weld_spin_button(u"minutes"_ustr))
1404
0
    , m_xSecondNF(m_xBuilder->weld_spin_button(u"seconds"_ustr))
1405
0
    , m_xMSecondNF(m_xBuilder->weld_spin_button(u"milliseconds"_ustr))
1406
0
{
1407
0
    m_xNegativeCB->set_active(rDuration.Negative);
1408
0
    m_xYearNF->set_value(rDuration.Years);
1409
0
    m_xMonthNF->set_value(rDuration.Months);
1410
0
    m_xDayNF->set_value(rDuration.Days);
1411
0
    m_xHourNF->set_value(rDuration.Hours);
1412
0
    m_xMinuteNF->set_value(rDuration.Minutes);
1413
0
    m_xSecondNF->set_value(rDuration.Seconds);
1414
0
    m_xMSecondNF->set_value(rDuration.NanoSeconds);
1415
0
}
1416
1417
util::Duration  DurationDialog_Impl::GetDuration() const
1418
0
{
1419
0
    util::Duration  aRet;
1420
0
    aRet.Negative = m_xNegativeCB->get_active();
1421
0
    aRet.Years = m_xYearNF->get_value();
1422
0
    aRet.Months = m_xMonthNF->get_value();
1423
0
    aRet.Days = m_xDayNF->get_value();
1424
0
    aRet.Hours  = m_xHourNF->get_value();
1425
0
    aRet.Minutes = m_xMinuteNF->get_value();
1426
0
    aRet.Seconds = m_xSecondNF->get_value();
1427
0
    aRet.NanoSeconds = m_xMSecondNF->get_value();
1428
0
    return aRet;
1429
0
}
1430
1431
CustomPropertiesDurationField::CustomPropertiesDurationField(std::unique_ptr<weld::Entry> xEntry,
1432
                                                             std::unique_ptr<weld::Button> xEditButton)
1433
0
    : m_xEntry(std::move(xEntry))
1434
0
    , m_xEditButton(std::move(xEditButton))
1435
0
{
1436
0
    m_xEditButton->connect_clicked(LINK(this, CustomPropertiesDurationField, ClickHdl));
1437
0
    SetDuration( util::Duration(false, 0, 0, 0, 0, 0, 0, 0) );
1438
0
}
1439
1440
void CustomPropertiesDurationField::set_visible(bool bVisible)
1441
0
{
1442
0
    m_xEntry->set_visible(bVisible);
1443
0
    m_xEditButton->set_visible(bVisible);
1444
0
}
1445
1446
void CustomPropertiesDurationField::SetDuration( const util::Duration& rDuration )
1447
0
{
1448
0
    m_aDuration = rDuration;
1449
0
    OUString sText = (rDuration.Negative ? OUString('-') : OUString('+')) +
1450
0
        SfxResId(SFX_ST_DURATION_FORMAT);
1451
0
    sText = sText.replaceFirst( "%1", OUString::number( rDuration.Years ) );
1452
0
    sText = sText.replaceFirst( "%2", OUString::number( rDuration.Months ) );
1453
0
    sText = sText.replaceFirst( "%3", OUString::number( rDuration.Days   ) );
1454
0
    sText = sText.replaceFirst( "%4", OUString::number( rDuration.Hours  ) );
1455
0
    sText = sText.replaceFirst( "%5", OUString::number( rDuration.Minutes) );
1456
0
    sText = sText.replaceFirst( "%6", OUString::number( rDuration.Seconds) );
1457
0
    m_xEntry->set_text(sText);
1458
0
}
1459
1460
IMPL_LINK(CustomPropertiesDurationField, ClickHdl, weld::Button&, rButton, void)
1461
0
{
1462
0
    m_xDurationDialog = std::make_shared<DurationDialog_Impl>(&rButton, GetDuration());
1463
0
    weld::DialogController::runAsync(m_xDurationDialog, [&](sal_Int32 response)
1464
0
    {
1465
0
        if (response == RET_OK)
1466
0
        {
1467
0
            SetDuration(m_xDurationDialog->GetDuration());
1468
0
        }
1469
0
    });
1470
0
}
1471
1472
CustomPropertiesDurationField::~CustomPropertiesDurationField()
1473
0
{
1474
0
    if (m_xDurationDialog)
1475
0
        m_xDurationDialog->response(RET_CANCEL);
1476
0
}
1477
1478
namespace
1479
{
1480
    void fillNameBox(weld::ComboBox& rNameBox)
1481
0
    {
1482
0
        for (const auto& rResId : SFX_CB_PROPERTY_STRINGARRAY)
1483
0
            rNameBox.append_text(SfxResId(rResId));
1484
0
        Size aSize(rNameBox.get_preferred_size());
1485
0
        rNameBox.set_size_request(aSize.Width(), aSize.Height());
1486
0
    }
1487
1488
    void fillTypeBox(weld::ComboBox& rTypeBox)
1489
0
    {
1490
0
        for (const auto& [rResId, rProperty] : SFX_LB_PROPERTY_STRINGARRAY)
1491
0
        {
1492
0
            OUString sId(OUString::number(rProperty));
1493
0
            rTypeBox.append(sId, SfxResId(rResId));
1494
0
        }
1495
0
        rTypeBox.set_active(0);
1496
0
        Size aSize(rTypeBox.get_preferred_size());
1497
0
        rTypeBox.set_size_request(aSize.Width(), aSize.Height());
1498
0
    }
1499
}
1500
1501
// struct CustomPropertyLine ---------------------------------------------
1502
CustomPropertyLine::CustomPropertyLine(CustomPropertiesWindow* pParent, weld::Widget* pContainer)
1503
0
    : m_pParent(pParent)
1504
0
    , m_xBuilder(Application::CreateBuilder(pContainer, u"sfx/ui/linefragment.ui"_ustr))
1505
0
    , m_xLine(m_xBuilder->weld_container(u"lineentry"_ustr))
1506
0
    , m_xNameBox(m_xBuilder->weld_combo_box(u"namebox"_ustr))
1507
0
    , m_xTypeBox(m_xBuilder->weld_combo_box(u"typebox"_ustr))
1508
0
    , m_xValueEdit(m_xBuilder->weld_entry(u"valueedit"_ustr))
1509
0
    , m_xDateTimeBox(m_xBuilder->weld_widget(u"datetimebox"_ustr))
1510
0
    , m_xDateField(new CustomPropertiesDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr))))
1511
0
    , m_xTimeField(new CustomPropertiesTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr)))
1512
0
    , m_xDurationBox(m_xBuilder->weld_widget(u"durationbox"_ustr))
1513
0
    , m_xDurationField(new CustomPropertiesDurationField(m_xBuilder->weld_entry(u"duration"_ustr),
1514
0
                                                         m_xBuilder->weld_button(u"durationbutton"_ustr)))
1515
0
    , m_xYesNoButton(new CustomPropertiesYesNoButton(m_xBuilder->weld_widget(u"yesno"_ustr),
1516
0
                                                     m_xBuilder->weld_radio_button(u"yes"_ustr),
1517
0
                                                     m_xBuilder->weld_radio_button(u"no"_ustr)))
1518
0
    , m_xRemoveButton(m_xBuilder->weld_button(u"remove"_ustr))
1519
0
    , m_bTypeLostFocus( false )
1520
0
{
1521
0
    fillNameBox(*m_xNameBox);
1522
0
    fillTypeBox(*m_xTypeBox);
1523
1524
0
    m_xTypeBox->connect_changed(LINK(this, CustomPropertyLine, TypeHdl));
1525
0
    m_xRemoveButton->connect_clicked(LINK(this, CustomPropertyLine, RemoveHdl));
1526
0
    m_xValueEdit->connect_focus_out(LINK(this, CustomPropertyLine, EditLoseFocusHdl));
1527
    //add lose focus handlers of date/time fields
1528
0
    m_xTypeBox->connect_focus_out(LINK(this, CustomPropertyLine, BoxLoseFocusHdl));
1529
0
}
1530
1531
void CustomPropertyLine::Clear()
1532
0
{
1533
0
    m_xNameBox->set_active(-1);
1534
0
    m_xValueEdit->set_text(OUString());
1535
1536
0
}
1537
1538
void CustomPropertyLine::Hide()
1539
0
{
1540
0
    m_xLine->hide();
1541
0
}
1542
1543
CustomPropertiesWindow::CustomPropertiesWindow(weld::Container& rParent, weld::Label& rHeaderAccName,
1544
                                               weld::Label& rHeaderAccType, weld::Label& rHeaderAccValue)
1545
0
    : m_nHeight(0)
1546
0
    , m_nLineHeight(0)
1547
0
    , m_nScrollPos(0)
1548
0
    , m_pCurrentLine(nullptr)
1549
0
    , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
1550
0
                         Application::GetSettings().GetLanguageTag().getLanguageType())
1551
0
    , m_aEditLoseFocusIdle("sfx2 CustomPropertiesWindow loseFocusIdle")
1552
0
    , m_aBoxLoseFocusIdle("sfx2 CustomPropertiesWindow m_aBoxLoseFocusIdle")
1553
0
    , m_rBody(rParent)
1554
0
    , m_rHeaderAccName(rHeaderAccName)
1555
0
    , m_rHeaderAccType(rHeaderAccType)
1556
0
    , m_rHeaderAccValue(rHeaderAccValue)
1557
0
{
1558
0
    m_aEditLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1559
0
    m_aEditLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, EditTimeoutHdl ) );
1560
0
    m_aBoxLoseFocusIdle.SetPriority( TaskPriority::LOWEST );
1561
0
    m_aBoxLoseFocusIdle.SetInvokeHandler( LINK( this, CustomPropertiesWindow, BoxTimeoutHdl ) );
1562
0
}
1563
1564
CustomPropertiesWindow::~CustomPropertiesWindow()
1565
0
{
1566
0
    m_aEditLoseFocusIdle.Stop();
1567
0
    m_aBoxLoseFocusIdle.Stop();
1568
1569
0
    m_pCurrentLine = nullptr;
1570
0
}
1571
1572
void CustomPropertyLine::DoTypeHdl(const weld::ComboBox& rBox)
1573
0
{
1574
0
    auto nType = rBox.get_active_id().toInt32();
1575
0
    m_xValueEdit->set_visible( (Custom_Type_Text == nType) || (Custom_Type_Number == nType) );
1576
0
    m_xDateTimeBox->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1577
0
    m_xDateField->set_visible( (Custom_Type_Date == nType) || (Custom_Type_Datetime == nType) );
1578
0
    m_xTimeField->set_visible( Custom_Type_Datetime == nType );
1579
0
    m_xDurationBox->set_visible( Custom_Type_Duration == nType );
1580
0
    m_xDurationField->set_visible( Custom_Type_Duration == nType );
1581
0
    m_xYesNoButton->set_visible( Custom_Type_Boolean == nType );
1582
0
}
1583
1584
IMPL_LINK(CustomPropertyLine, TypeHdl, weld::ComboBox&, rBox, void)
1585
0
{
1586
0
    DoTypeHdl(rBox);
1587
0
}
1588
1589
void CustomPropertiesWindow::Remove(const CustomPropertyLine* pLine)
1590
0
{
1591
0
    StoreCustomProperties();
1592
1593
0
    auto pFound = std::find_if( m_aCustomPropertiesLines.begin(), m_aCustomPropertiesLines.end(),
1594
0
                    [&] (const std::unique_ptr<CustomPropertyLine>& p) { return p.get() == pLine; });
1595
0
    if ( pFound != m_aCustomPropertiesLines.end() )
1596
0
    {
1597
0
        sal_uInt32 nLineNumber = pFound - m_aCustomPropertiesLines.begin();
1598
0
        sal_uInt32 nDataModelIndex = GetCurrentDataModelPosition() + nLineNumber;
1599
0
        m_aCustomProperties.erase(m_aCustomProperties.begin() + nDataModelIndex);
1600
1601
0
        ReloadLinesContent();
1602
0
    }
1603
1604
0
    m_aRemovedHdl.Call(nullptr);
1605
0
}
1606
1607
IMPL_LINK_NOARG(CustomPropertyLine, RemoveHdl, weld::Button&, void)
1608
0
{
1609
0
    m_pParent->Remove(this);
1610
0
}
1611
1612
void CustomPropertiesWindow::EditLoseFocus(CustomPropertyLine* pLine)
1613
0
{
1614
0
    m_pCurrentLine = pLine;
1615
0
    m_aEditLoseFocusIdle.Start();
1616
0
}
1617
1618
IMPL_LINK_NOARG(CustomPropertyLine, EditLoseFocusHdl, weld::Widget&, void)
1619
0
{
1620
0
    if (!m_bTypeLostFocus)
1621
0
        m_pParent->EditLoseFocus(this);
1622
0
    else
1623
0
        m_bTypeLostFocus = false;
1624
0
}
1625
1626
void CustomPropertiesWindow::BoxLoseFocus(CustomPropertyLine* pLine)
1627
0
{
1628
0
    m_pCurrentLine = pLine;
1629
0
    m_aBoxLoseFocusIdle.Start();
1630
0
}
1631
1632
IMPL_LINK_NOARG(CustomPropertyLine, BoxLoseFocusHdl, weld::Widget&, void)
1633
0
{
1634
0
    m_pParent->BoxLoseFocus(this);
1635
0
}
1636
1637
IMPL_LINK_NOARG(CustomPropertiesWindow, EditTimeoutHdl, Timer *, void)
1638
0
{
1639
0
    ValidateLine( m_pCurrentLine, false );
1640
0
}
1641
1642
IMPL_LINK_NOARG(CustomPropertiesWindow, BoxTimeoutHdl, Timer *, void)
1643
0
{
1644
0
    ValidateLine( m_pCurrentLine, true );
1645
0
}
1646
1647
bool CustomPropertiesWindow::IsLineValid( CustomPropertyLine* pLine ) const
1648
0
{
1649
0
    bool bIsValid = true;
1650
0
    pLine->m_bTypeLostFocus = false;
1651
0
    auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1652
0
    OUString sValue = pLine->m_xValueEdit->get_text();
1653
0
    if ( sValue.isEmpty() )
1654
0
        return true;
1655
1656
0
    sal_uInt32 nIndex = NUMBERFORMAT_ENTRY_NOT_FOUND;
1657
0
    if ( Custom_Type_Number == nType )
1658
        // tdf#116214 Scientific format allows to use also standard numbers
1659
0
        nIndex = const_cast< SvNumberFormatter& >(
1660
0
            m_aNumberFormatter ).GetFormatIndex( NF_SCIENTIFIC_000E00 );
1661
0
    else if ( Custom_Type_Date == nType )
1662
0
        nIndex = const_cast< SvNumberFormatter& >(
1663
0
            m_aNumberFormatter).GetFormatIndex( NF_DATE_SYS_DDMMYYYY );
1664
1665
0
    if ( nIndex != NUMBERFORMAT_ENTRY_NOT_FOUND )
1666
0
    {
1667
0
        sal_uInt32 nTemp = nIndex;
1668
0
        double fDummy = 0.0;
1669
0
        bIsValid = const_cast< SvNumberFormatter& >(
1670
0
            m_aNumberFormatter ).IsNumberFormat( sValue, nIndex, fDummy );
1671
0
        if ( bIsValid && nTemp != nIndex )
1672
            // sValue is a number but the format doesn't match the index
1673
0
            bIsValid = false;
1674
0
    }
1675
1676
0
    return bIsValid;
1677
0
}
1678
1679
void CustomPropertiesWindow::ValidateLine( CustomPropertyLine* pLine, bool bIsFromTypeBox )
1680
0
{
1681
0
    if (pLine && !IsLineValid(pLine))
1682
0
    {
1683
0
        if ( bIsFromTypeBox ) // LoseFocus of TypeBox
1684
0
            pLine->m_bTypeLostFocus = true;
1685
0
        std::unique_ptr<weld::MessageDialog> xMessageBox(Application::CreateMessageDialog(&m_rBody,
1686
0
                                                         VclMessageType::Question, VclButtonsType::OkCancel, SfxResId(STR_SFX_QUERY_WRONG_TYPE)));
1687
0
        if (xMessageBox->run() == RET_OK)
1688
0
            pLine->m_xTypeBox->set_active_id(OUString::number(Custom_Type_Text));
1689
0
        else
1690
0
            pLine->m_xValueEdit->grab_focus();
1691
0
    }
1692
0
}
1693
1694
void CustomPropertiesWindow::SetVisibleLineCount(sal_uInt32 nCount)
1695
0
{
1696
0
    while (GetExistingLineCount() < nCount)
1697
0
    {
1698
0
        CreateNewLine();
1699
0
    }
1700
0
}
1701
1702
void CustomPropertiesWindow::AddLine(const OUString& sName, Any const & rAny)
1703
0
{
1704
0
    m_aCustomProperties.push_back(std::unique_ptr<CustomProperty>(new CustomProperty(sName, rAny)));
1705
0
    ReloadLinesContent();
1706
0
}
1707
1708
void CustomPropertiesWindow::CreateNewLine()
1709
0
{
1710
0
    CustomPropertyLine* pNewLine = new CustomPropertyLine(this, &m_rBody);
1711
0
    pNewLine->m_xNameBox->set_accessible_name(m_rHeaderAccName.get_label());
1712
0
    pNewLine->m_xTypeBox->set_accessible_name(m_rHeaderAccType.get_label());
1713
0
    pNewLine->m_xValueEdit->set_accessible_name(m_rHeaderAccValue.get_label());
1714
1715
0
    m_aCustomPropertiesLines.emplace_back( pNewLine );
1716
1717
    // for ui-testing. Distinguish the elements in the lines
1718
0
    sal_uInt16 nSize = m_aCustomPropertiesLines.size();
1719
0
    pNewLine->m_xNameBox->set_buildable_name(pNewLine->m_xNameBox->get_buildable_name()
1720
0
                                             + OUString::number(nSize));
1721
0
    pNewLine->m_xTypeBox->set_buildable_name(pNewLine->m_xTypeBox->get_buildable_name()
1722
0
                                             + OUString::number(nSize));
1723
0
    pNewLine->m_xValueEdit->set_buildable_name(pNewLine->m_xValueEdit->get_buildable_name()
1724
0
                                               + OUString::number(nSize));
1725
0
    pNewLine->m_xRemoveButton->set_buildable_name(pNewLine->m_xRemoveButton->get_buildable_name()
1726
0
                                                  + OUString::number(nSize));
1727
1728
0
    pNewLine->DoTypeHdl(*pNewLine->m_xTypeBox);
1729
0
}
1730
1731
bool CustomPropertiesWindow::AreAllLinesValid() const
1732
0
{
1733
0
    bool bRet = true;
1734
0
    for ( std::unique_ptr<CustomPropertyLine> const & pLine : m_aCustomPropertiesLines )
1735
0
    {
1736
0
        if ( !IsLineValid( pLine.get() ) )
1737
0
        {
1738
0
            bRet = false;
1739
0
            break;
1740
0
        }
1741
0
    }
1742
1743
0
    return bRet;
1744
0
}
1745
1746
void CustomPropertiesWindow::ClearAllLines()
1747
0
{
1748
0
    for (auto& pLine : m_aCustomPropertiesLines)
1749
0
    {
1750
0
        pLine->Clear();
1751
0
    }
1752
0
    m_pCurrentLine = nullptr;
1753
0
    m_aCustomProperties.clear();
1754
0
    m_nScrollPos = 0;
1755
0
}
1756
1757
void CustomPropertiesWindow::DoScroll( sal_Int32 nNewPos )
1758
0
{
1759
0
    StoreCustomProperties();
1760
0
    m_nScrollPos += nNewPos;
1761
0
    ReloadLinesContent();
1762
0
}
1763
1764
Sequence< beans::PropertyValue > CustomPropertiesWindow::GetCustomProperties()
1765
0
{
1766
0
    StoreCustomProperties();
1767
1768
0
    Sequence< beans::PropertyValue > aPropertiesSeq(GetTotalLineCount());
1769
0
    std::transform(
1770
0
        m_aCustomProperties.begin(), m_aCustomProperties.end(), aPropertiesSeq.getArray(),
1771
0
        [](const auto& el) { return comphelper::makePropertyValue(el->m_sName, el->m_aValue); });
1772
1773
0
    return aPropertiesSeq;
1774
0
}
1775
1776
CustomPropertiesTimeField::CustomPropertiesTimeField(std::unique_ptr<weld::FormattedSpinButton> xTimeField)
1777
0
    : m_xTimeField(std::move(xTimeField))
1778
0
    , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
1779
0
    , m_isUTC(false)
1780
0
{
1781
0
    m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
1782
0
    m_xFormatter->EnableEmptyField(false);
1783
0
}
1784
1785
tools::Time CustomPropertiesTimeField::get_value() const
1786
0
{
1787
0
    return m_xFormatter->GetTime();
1788
0
}
1789
1790
void CustomPropertiesTimeField::set_value(const tools::Time& rTime)
1791
0
{
1792
0
    m_xFormatter->SetTime(rTime);
1793
0
}
1794
1795
CustomPropertiesTimeField::~CustomPropertiesTimeField()
1796
0
{
1797
0
}
1798
1799
CustomPropertiesDateField::CustomPropertiesDateField(SvtCalendarBox* pDateField)
1800
0
    : m_xDateField(pDateField)
1801
0
{
1802
0
    DateTime aDateTime(DateTime::SYSTEM);
1803
0
    m_xDateField->set_date(aDateTime);
1804
0
}
1805
1806
void CustomPropertiesDateField::set_visible(bool bVisible)
1807
0
{
1808
0
    m_xDateField->set_visible(bVisible);
1809
0
}
1810
1811
Date CustomPropertiesDateField::get_date() const
1812
0
{
1813
0
    return m_xDateField->get_date();
1814
0
}
1815
1816
void CustomPropertiesDateField::set_date(const Date& rDate)
1817
0
{
1818
0
    m_xDateField->set_date(rDate);
1819
0
}
1820
1821
CustomPropertiesDateField::~CustomPropertiesDateField()
1822
0
{
1823
0
}
1824
1825
void CustomPropertiesWindow::StoreCustomProperties()
1826
0
{
1827
0
    sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1828
1829
0
    for (sal_uInt32 i = 0; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1830
0
    {
1831
0
        CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1832
1833
0
        OUString sPropertyName = pLine->m_xNameBox->get_active_text();
1834
0
        if (!sPropertyName.isEmpty())
1835
0
        {
1836
0
            m_aCustomProperties[nDataModelPos + i]->m_sName = sPropertyName;
1837
0
            auto nType = pLine->m_xTypeBox->get_active_id().toInt32();
1838
0
            if (Custom_Type_Number == nType)
1839
0
            {
1840
0
                double nValue = 0;
1841
0
                sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1842
0
                bool bIsNum = m_aNumberFormatter.
1843
0
                    IsNumberFormat(pLine->m_xValueEdit->get_text(), nIndex, nValue);
1844
0
                if (bIsNum)
1845
0
                    m_aCustomProperties[nDataModelPos + i]->m_aValue <<= nValue;
1846
0
            }
1847
0
            else if (Custom_Type_Boolean == nType)
1848
0
            {
1849
0
                bool bValue = pLine->m_xYesNoButton->IsYesChecked();
1850
0
                m_aCustomProperties[nDataModelPos + i]->m_aValue <<= bValue;
1851
0
            }
1852
0
            else if (Custom_Type_Datetime == nType)
1853
0
            {
1854
0
                Date aTmpDate = pLine->m_xDateField->get_date();
1855
0
                tools::Time aTmpTime = pLine->m_xTimeField->get_value();
1856
0
                util::DateTime const aDateTime(aTmpTime.GetNanoSec(),
1857
0
                    aTmpTime.GetSec(), aTmpTime.GetMin(), aTmpTime.GetHour(),
1858
0
                    aTmpDate.GetDay(), aTmpDate.GetMonth(), aTmpDate.GetYear(),
1859
0
                    pLine->m_xTimeField->m_isUTC);
1860
0
                if (pLine->m_xDateField->m_TZ)
1861
0
                {
1862
0
                    m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateTimeWithTimezone(
1863
0
                        aDateTime, *pLine->m_xDateField->m_TZ);
1864
0
                }
1865
0
                else
1866
0
                {
1867
0
                    m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDateTime;
1868
0
                }
1869
0
            }
1870
0
            else if (Custom_Type_Date == nType)
1871
0
            {
1872
0
                Date aTmpDate = pLine->m_xDateField->get_date();
1873
0
                util::Date const aDate(aTmpDate.GetDay(), aTmpDate.GetMonth(),
1874
0
                    aTmpDate.GetYear());
1875
0
                if (pLine->m_xDateField->m_TZ)
1876
0
                {
1877
0
                    m_aCustomProperties[nDataModelPos + i]->m_aValue <<= util::DateWithTimezone(
1878
0
                        aDate, *pLine->m_xDateField->m_TZ);
1879
0
                }
1880
0
                else
1881
0
                {
1882
0
                    m_aCustomProperties[nDataModelPos + i]->m_aValue <<= aDate;
1883
0
                }
1884
0
            }
1885
0
            else if (Custom_Type_Duration == nType)
1886
0
            {
1887
0
                m_aCustomProperties[nDataModelPos + i]->m_aValue <<= pLine->m_xDurationField->GetDuration();
1888
0
            }
1889
0
            else
1890
0
            {
1891
0
                OUString sValue(pLine->m_xValueEdit->get_text());
1892
0
                m_aCustomProperties[nDataModelPos + i]->m_aValue <<= sValue;
1893
0
            }
1894
0
        }
1895
0
    }
1896
0
}
1897
1898
void CustomPropertiesWindow::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
1899
0
{
1900
0
    m_aCustomProperties = std::move(rProperties);
1901
0
    ReloadLinesContent();
1902
0
}
1903
1904
void CustomPropertiesWindow::ReloadLinesContent()
1905
0
{
1906
0
    double nTmpValue = 0;
1907
0
    bool bTmpValue = false;
1908
0
    OUString sTmpValue;
1909
0
    util::DateTime aTmpDateTime;
1910
0
    util::Date aTmpDate;
1911
0
    util::DateTimeWithTimezone aTmpDateTimeTZ;
1912
0
    util::DateWithTimezone aTmpDateTZ;
1913
0
    util::Duration aTmpDuration;
1914
0
    SvtSysLocale aSysLocale;
1915
0
    const LocaleDataWrapper& rLocaleWrapper = aSysLocale.GetLocaleData();
1916
0
    CustomProperties nType = Custom_Type_Unknown;
1917
0
    OUString sValue;
1918
1919
0
    sal_uInt32 nDataModelPos = GetCurrentDataModelPosition();
1920
0
    sal_uInt32 i = 0;
1921
1922
0
    for (; nDataModelPos + i < GetTotalLineCount() && i < GetExistingLineCount(); i++)
1923
0
    {
1924
0
        const OUString& rName = m_aCustomProperties[nDataModelPos + i]->m_sName;
1925
0
        const css::uno::Any& rAny = m_aCustomProperties[nDataModelPos + i]->m_aValue;
1926
1927
0
        CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
1928
0
        pLine->Clear();
1929
1930
0
        pLine->m_xNameBox->set_entry_text(rName);
1931
0
        pLine->m_xLine->show();
1932
1933
0
        if (!rAny.hasValue())
1934
0
        {
1935
0
            pLine->m_xValueEdit->set_text(OUString());
1936
0
        }
1937
0
        else if (rAny >>= nTmpValue)
1938
0
        {
1939
0
            sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex(NF_NUMBER_SYSTEM);
1940
0
            sValue = m_aNumberFormatter.GetInputLineString(nTmpValue, nIndex);
1941
0
            pLine->m_xValueEdit->set_text(sValue);
1942
0
            nType = Custom_Type_Number;
1943
0
        }
1944
0
        else if (rAny >>= bTmpValue)
1945
0
        {
1946
0
            sValue = (bTmpValue ? rLocaleWrapper.getTrueWord() : rLocaleWrapper.getFalseWord());
1947
0
            nType = Custom_Type_Boolean;
1948
0
        }
1949
0
        else if (rAny >>= sTmpValue)
1950
0
        {
1951
0
            pLine->m_xValueEdit->set_text(sTmpValue);
1952
0
            nType = Custom_Type_Text;
1953
0
        }
1954
0
        else if (rAny >>= aTmpDate)
1955
0
        {
1956
0
            pLine->m_xDateField->set_date(Date(aTmpDate));
1957
0
            nType = Custom_Type_Date;
1958
0
        }
1959
0
        else if (rAny >>= aTmpDateTime)
1960
0
        {
1961
0
            pLine->m_xDateField->set_date(Date(aTmpDateTime));
1962
0
            pLine->m_xTimeField->set_value(tools::Time(aTmpDateTime));
1963
0
            pLine->m_xTimeField->m_isUTC = aTmpDateTime.IsUTC;
1964
0
            nType = Custom_Type_Datetime;
1965
0
        }
1966
0
        else if (rAny >>= aTmpDateTZ)
1967
0
        {
1968
0
            pLine->m_xDateField->set_date(Date(aTmpDateTZ.DateInTZ.Day,
1969
0
                aTmpDateTZ.DateInTZ.Month, aTmpDateTZ.DateInTZ.Year));
1970
0
            pLine->m_xDateField->m_TZ = aTmpDateTZ.Timezone;
1971
0
            nType = Custom_Type_Date;
1972
0
        }
1973
1974
0
        else if (rAny >>= aTmpDateTimeTZ)
1975
0
        {
1976
0
            util::DateTime const& rDT(aTmpDateTimeTZ.DateTimeInTZ);
1977
0
            pLine->m_xDateField->set_date(Date(rDT));
1978
0
            pLine->m_xTimeField->set_value(tools::Time(rDT));
1979
0
            pLine->m_xTimeField->m_isUTC = rDT.IsUTC;
1980
0
            pLine->m_xDateField->m_TZ = aTmpDateTimeTZ.Timezone;
1981
0
            nType = Custom_Type_Datetime;
1982
0
        }
1983
0
        else if (rAny >>= aTmpDuration)
1984
0
        {
1985
0
            nType = Custom_Type_Duration;
1986
0
            pLine->m_xDurationField->SetDuration(aTmpDuration);
1987
0
        }
1988
1989
0
        if (Custom_Type_Boolean == nType)
1990
0
        {
1991
0
            if (bTmpValue)
1992
0
                pLine->m_xYesNoButton->CheckYes();
1993
0
            else
1994
0
                pLine->m_xYesNoButton->CheckNo();
1995
0
        }
1996
0
        pLine->m_xTypeBox->set_active_id(OUString::number(nType));
1997
1998
0
        pLine->DoTypeHdl(*pLine->m_xTypeBox);
1999
0
    }
2000
2001
    // tdf#132667 - grab focus on the last inserted property
2002
0
    if (i > 0 && m_aCustomProperties[nDataModelPos + i - 1]->m_sName.isEmpty())
2003
0
    {
2004
0
        CustomPropertyLine* pLine = m_aCustomPropertiesLines[i - 1].get();
2005
0
        pLine->m_xNameBox->grab_focus();
2006
0
    }
2007
2008
0
    while (nDataModelPos + i >= GetTotalLineCount() && i < GetExistingLineCount())
2009
0
    {
2010
0
        CustomPropertyLine* pLine = m_aCustomPropertiesLines[i].get();
2011
0
        pLine->Hide();
2012
0
        i++;
2013
0
    }
2014
0
}
2015
2016
CustomPropertiesControl::CustomPropertiesControl()
2017
0
    : m_nThumbPos(0)
2018
0
{
2019
0
}
2020
2021
void CustomPropertiesControl::Init(weld::Builder& rBuilder)
2022
0
{
2023
0
    m_xBox = rBuilder.weld_widget(u"box"_ustr);
2024
0
    m_xBody = rBuilder.weld_container(u"properties"_ustr);
2025
2026
0
    m_xName = rBuilder.weld_label(u"name"_ustr);
2027
0
    m_xType = rBuilder.weld_label(u"type"_ustr);
2028
0
    m_xValue = rBuilder.weld_label(u"value"_ustr);
2029
0
    m_xVertScroll = rBuilder.weld_scrolled_window(u"scroll"_ustr, true);
2030
0
    m_xPropertiesWin.reset(new CustomPropertiesWindow(*m_xBody, *m_xName, *m_xType, *m_xValue));
2031
2032
0
    m_xBox->set_stack_background();
2033
0
    m_xVertScroll->show();
2034
2035
0
    std::unique_ptr<CustomPropertyLine> xNewLine(new CustomPropertyLine(m_xPropertiesWin.get(), m_xBody.get()));
2036
0
    Size aLineSize(xNewLine->m_xLine->get_preferred_size());
2037
0
    m_xPropertiesWin->SetLineHeight(aLineSize.Height() + 6);
2038
0
    m_xBody->set_size_request(aLineSize.Width() + 6, -1);
2039
0
    auto nHeight = aLineSize.Height() * 8;
2040
0
    m_xVertScroll->set_size_request(-1, nHeight + 6);
2041
2042
0
    m_xPropertiesWin->SetHeight(nHeight);
2043
0
    m_xVertScroll->connect_size_allocate(LINK(this, CustomPropertiesControl, ResizeHdl));
2044
2045
0
    m_xName->set_size_request(xNewLine->m_xNameBox->get_preferred_size().Width(), -1);
2046
0
    m_xType->set_size_request(xNewLine->m_xTypeBox->get_preferred_size().Width(), -1);
2047
0
    m_xValue->set_size_request(xNewLine->m_xValueEdit->get_preferred_size().Width(), -1);
2048
2049
0
    m_xBody->move(xNewLine->m_xLine.get(), nullptr);
2050
0
    xNewLine.reset();
2051
2052
0
    m_xPropertiesWin->SetRemovedHdl( LINK( this, CustomPropertiesControl, RemovedHdl ) );
2053
2054
0
    m_xVertScroll->vadjustment_set_upper(0);
2055
0
    m_xVertScroll->vadjustment_set_page_size(0xFFFF);
2056
2057
0
    Link<weld::ScrolledWindow&,void> aScrollLink = LINK( this, CustomPropertiesControl, ScrollHdl );
2058
0
    m_xVertScroll->connect_vadjustment_value_changed(aScrollLink);
2059
2060
0
    ResizeHdl(Size(-1, nHeight));
2061
0
}
2062
2063
IMPL_LINK(CustomPropertiesControl, ResizeHdl, const Size&, rSize, void)
2064
0
{
2065
0
    int nHeight = rSize.Height() - 6;
2066
0
    if (nHeight == m_xPropertiesWin->GetHeight())
2067
0
        return;
2068
0
    m_xPropertiesWin->SetHeight(nHeight);
2069
0
    sal_Int32 nScrollOffset = m_xPropertiesWin->GetLineHeight();
2070
0
    sal_Int32 nVisibleEntries = nHeight / nScrollOffset;
2071
0
    m_xPropertiesWin->SetVisibleLineCount( nVisibleEntries );
2072
0
    m_xVertScroll->vadjustment_set_page_increment( nVisibleEntries - 1 );
2073
0
    m_xVertScroll->vadjustment_set_page_size( nVisibleEntries );
2074
0
    m_xPropertiesWin->ReloadLinesContent();
2075
0
}
2076
2077
CustomPropertiesControl::~CustomPropertiesControl()
2078
0
{
2079
0
}
2080
2081
IMPL_LINK( CustomPropertiesControl, ScrollHdl, weld::ScrolledWindow&, rScrollBar, void )
2082
0
{
2083
0
    sal_Int32 nOffset = m_xPropertiesWin->GetLineHeight();
2084
0
    int nThumbPos = rScrollBar.vadjustment_get_value();
2085
0
    nOffset *= ( m_nThumbPos - nThumbPos );
2086
0
    m_nThumbPos = nThumbPos;
2087
0
    m_xPropertiesWin->DoScroll( nOffset );
2088
0
}
2089
2090
IMPL_LINK_NOARG(CustomPropertiesControl, RemovedHdl, void*, void)
2091
0
{
2092
0
    auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2093
0
    m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2094
0
    if (m_xPropertiesWin->GetTotalLineCount() > m_xPropertiesWin->GetExistingLineCount())
2095
0
    {
2096
0
        m_xVertScroll->vadjustment_set_value(nLineCount - 1);
2097
0
        ScrollHdl(*m_xVertScroll);
2098
0
    }
2099
0
}
2100
2101
void CustomPropertiesControl::AddLine( Any const & rAny )
2102
0
{
2103
0
    m_xPropertiesWin->AddLine( OUString(), rAny );
2104
0
    auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2105
0
    m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2106
0
    if (m_xPropertiesWin->GetHeight() < nLineCount * m_xPropertiesWin->GetLineHeight())
2107
0
    {
2108
0
        m_xVertScroll->vadjustment_set_value(nLineCount + 1);
2109
0
        ScrollHdl(*m_xVertScroll);
2110
0
    }
2111
0
}
2112
2113
void CustomPropertiesControl::SetCustomProperties(std::vector< std::unique_ptr<CustomProperty> >&& rProperties)
2114
0
{
2115
0
    m_xPropertiesWin->SetCustomProperties(std::move(rProperties));
2116
0
    auto nLineCount = m_xPropertiesWin->GetTotalLineCount();
2117
0
    m_xVertScroll->vadjustment_set_upper(nLineCount + 1);
2118
0
}
2119
2120
// class SfxCustomPropertiesPage -----------------------------------------
2121
SfxCustomPropertiesPage::SfxCustomPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet )
2122
0
    : SfxTabPage(pPage, pController, u"sfx/ui/custominfopage.ui"_ustr, u"CustomInfoPage"_ustr, &rItemSet)
2123
0
    , m_xPropertiesCtrl(new CustomPropertiesControl)
2124
0
    , m_xAdd(m_xBuilder->weld_button(u"add"_ustr))
2125
0
{
2126
0
    m_xPropertiesCtrl->Init(*m_xBuilder);
2127
0
    m_xAdd->connect_clicked(LINK(this, SfxCustomPropertiesPage, AddHdl));
2128
0
}
2129
2130
SfxCustomPropertiesPage::~SfxCustomPropertiesPage()
2131
0
{
2132
0
    m_xPropertiesCtrl.reset();
2133
0
}
2134
2135
IMPL_LINK_NOARG(SfxCustomPropertiesPage, AddHdl, weld::Button&, void)
2136
0
{
2137
    // tdf#115853: reload current lines before adding a brand new one
2138
    // indeed the info are deleted by ClearCustomProperties
2139
    // each time SfxDocumentInfoItem destructor is called
2140
0
    SfxDocumentInfoItem pInfo;
2141
0
    const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2142
0
    for ( const auto& rProperty : aPropertySeq )
2143
0
    {
2144
0
        if ( !rProperty.Name.isEmpty() )
2145
0
        {
2146
0
            pInfo.AddCustomProperty( rProperty.Name, rProperty.Value );
2147
0
        }
2148
0
    }
2149
2150
0
    Any aAny;
2151
0
    m_xPropertiesCtrl->AddLine(aAny);
2152
0
}
2153
2154
bool SfxCustomPropertiesPage::FillItemSet( SfxItemSet* rSet )
2155
0
{
2156
0
    const SfxDocumentInfoItem* pItem = nullptr;
2157
0
    SfxDocumentInfoItem* pInfo = nullptr;
2158
0
    bool bMustDelete = false;
2159
2160
0
    if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2161
0
    {
2162
0
        pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2163
0
        if (!pItem)
2164
0
            pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2165
0
        else
2166
0
        {
2167
0
            bMustDelete = true;
2168
0
            pInfo = new SfxDocumentInfoItem( *pItem );
2169
0
        }
2170
0
    }
2171
2172
0
    if ( pInfo )
2173
0
    {
2174
        // If it's a CMIS document, we can't save custom properties
2175
0
        if ( pInfo->isCmisDocument( ) )
2176
0
        {
2177
0
            if ( bMustDelete )
2178
0
                delete pInfo;
2179
0
            return false;
2180
0
        }
2181
2182
0
        pInfo->ClearCustomProperties();
2183
0
        const Sequence< beans::PropertyValue > aPropertySeq = m_xPropertiesCtrl->GetCustomProperties();
2184
0
        for ( const auto& rProperty : aPropertySeq )
2185
0
        {
2186
0
            if ( !rProperty.Name.isEmpty() )
2187
0
                pInfo->AddCustomProperty( rProperty.Name, rProperty.Value );
2188
0
        }
2189
0
    }
2190
2191
0
    if (pInfo)
2192
0
    {
2193
0
        rSet->Put(*pInfo);
2194
0
        if ( bMustDelete )
2195
0
            delete pInfo;
2196
0
    }
2197
0
    return true;
2198
0
}
2199
2200
void SfxCustomPropertiesPage::Reset( const SfxItemSet* rItemSet )
2201
0
{
2202
0
    m_xPropertiesCtrl->ClearAllLines();
2203
0
    const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2204
0
    std::vector< std::unique_ptr<CustomProperty> > aCustomProps = rInfoItem.GetCustomProperties();
2205
    // tdf#123919 - sort custom document properties
2206
0
    auto const sort = comphelper::string::NaturalStringSorter(
2207
0
        comphelper::getProcessComponentContext(),
2208
0
        Application::GetSettings().GetLanguageTag().getLocale());
2209
0
    std::sort(aCustomProps.begin(), aCustomProps.end(),
2210
0
              [&sort](const std::unique_ptr<CustomProperty>& rLHS,
2211
0
                      const std::unique_ptr<CustomProperty>& rRHS) {
2212
0
                  return sort.compare(rLHS->m_sName, rRHS->m_sName) < 0;
2213
0
              });
2214
0
    m_xPropertiesCtrl->SetCustomProperties(std::move(aCustomProps));
2215
0
}
2216
2217
DeactivateRC SfxCustomPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2218
0
{
2219
0
    DeactivateRC nRet = DeactivateRC::LeavePage;
2220
0
    if ( !m_xPropertiesCtrl->AreAllLinesValid() )
2221
0
        nRet = DeactivateRC::KeepPage;
2222
0
    return nRet;
2223
0
}
2224
2225
std::unique_ptr<SfxTabPage> SfxCustomPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2226
0
{
2227
0
    return std::make_unique<SfxCustomPropertiesPage>(pPage, pController, *rItemSet);
2228
0
}
2229
2230
CmisValue::CmisValue(weld::Widget* pParent, const OUString& aStr)
2231
0
    : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2232
0
    , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2233
0
    , m_xValueEdit(m_xBuilder->weld_entry(u"value"_ustr))
2234
0
{
2235
0
    m_xValueEdit->show();
2236
0
    m_xValueEdit->set_text(aStr);
2237
0
}
2238
2239
CmisDateTime::CmisDateTime(weld::Widget* pParent, const util::DateTime& aDateTime)
2240
0
    : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2241
0
    , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2242
0
    , m_xDateField(new SvtCalendarBox(m_xBuilder->weld_menu_button(u"date"_ustr)))
2243
0
    , m_xTimeField(m_xBuilder->weld_formatted_spin_button(u"time"_ustr))
2244
0
    , m_xFormatter(new weld::TimeFormatter(*m_xTimeField))
2245
0
{
2246
0
    m_xFormatter->SetExtFormat(ExtTimeFieldFormat::LongDuration);
2247
0
    m_xFormatter->EnableEmptyField(false);
2248
2249
0
    m_xDateField->show();
2250
0
    m_xTimeField->show();
2251
0
    m_xDateField->set_date(Date(aDateTime));
2252
0
    m_xFormatter->SetTime(tools::Time(aDateTime));
2253
0
}
2254
2255
CmisYesNo::CmisYesNo(weld::Widget* pParent, bool bValue)
2256
0
    : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2257
0
    , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2258
0
    , m_xYesButton(m_xBuilder->weld_radio_button(u"yes"_ustr))
2259
0
    , m_xNoButton(m_xBuilder->weld_radio_button(u"no"_ustr))
2260
0
{
2261
0
    m_xYesButton->show();
2262
0
    m_xNoButton->show();
2263
0
    if (bValue)
2264
0
        m_xYesButton->set_active(true);
2265
0
    else
2266
0
        m_xNoButton->set_active(true);
2267
0
}
2268
2269
// struct CmisPropertyLine ---------------------------------------------
2270
CmisPropertyLine::CmisPropertyLine(weld::Widget* pParent)
2271
0
    : m_xBuilder(Application::CreateBuilder(pParent, u"sfx/ui/cmisline.ui"_ustr))
2272
0
    , m_sType(CMIS_TYPE_STRING)
2273
0
    , m_bUpdatable(false)
2274
0
    , m_bRequired(false)
2275
0
    , m_bMultiValued(false)
2276
0
    , m_bOpenChoice(false)
2277
0
    , m_xFrame(m_xBuilder->weld_frame(u"CmisFrame"_ustr))
2278
0
    , m_xName(m_xBuilder->weld_label(u"name"_ustr))
2279
0
    , m_xType(m_xBuilder->weld_label(u"type"_ustr))
2280
0
{
2281
0
    m_xFrame->set_sensitive(true);
2282
0
}
2283
2284
CmisPropertyLine::~CmisPropertyLine( )
2285
0
{
2286
0
}
2287
2288
// class CmisPropertiesWindow -----------------------------------------
2289
2290
CmisPropertiesWindow::CmisPropertiesWindow(std::unique_ptr<weld::Container> xParent)
2291
0
    : m_xBox(std::move(xParent))
2292
0
    , m_aNumberFormatter(::comphelper::getProcessComponentContext(),
2293
0
                         Application::GetSettings().GetLanguageTag().getLanguageType())
2294
0
{
2295
0
}
2296
2297
CmisPropertiesWindow::~CmisPropertiesWindow()
2298
0
{
2299
0
}
2300
2301
void CmisPropertiesWindow::ClearAllLines()
2302
0
{
2303
0
    m_aCmisPropertiesLines.clear();
2304
0
}
2305
2306
void CmisPropertiesWindow::AddLine( const OUString& sId, const OUString& sName,
2307
                                    const OUString& sType, const bool bUpdatable,
2308
                                    const bool bRequired, const bool bMultiValued,
2309
                                    const bool bOpenChoice, Any& /*aChoices*/, Any const & rAny )
2310
0
{
2311
0
    std::unique_ptr<CmisPropertyLine> pNewLine(new CmisPropertyLine(m_xBox.get()));
2312
2313
0
    pNewLine->m_sId = sId;
2314
0
    pNewLine->m_sType = sType;
2315
0
    pNewLine->m_bUpdatable = bUpdatable;
2316
0
    pNewLine->m_bRequired = bRequired;
2317
0
    pNewLine->m_bMultiValued = bMultiValued;
2318
0
    pNewLine->m_bOpenChoice = bOpenChoice;
2319
2320
0
    if ( sType == CMIS_TYPE_INTEGER )
2321
0
    {
2322
0
        Sequence< sal_Int64 > seqValue;
2323
0
        rAny >>= seqValue;
2324
0
        sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2325
0
        for (const auto& rValue : seqValue)
2326
0
        {
2327
0
            OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2328
0
            std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2329
0
            pValue->m_xValueEdit->set_editable(bUpdatable);
2330
0
            pNewLine->m_aValues.push_back( std::move(pValue) );
2331
0
        }
2332
0
    }
2333
0
    else if ( sType == CMIS_TYPE_DECIMAL )
2334
0
    {
2335
0
        Sequence< double > seqValue;
2336
0
        rAny >>= seqValue;
2337
0
        sal_uInt32 nIndex = m_aNumberFormatter.GetFormatIndex( NF_NUMBER_SYSTEM );
2338
0
        for (const auto& rValue : seqValue)
2339
0
        {
2340
0
            OUString sValue = m_aNumberFormatter.GetInputLineString( rValue, nIndex );
2341
0
            std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), sValue));
2342
0
            pValue->m_xValueEdit->set_editable(bUpdatable);
2343
0
            pNewLine->m_aValues.push_back( std::move(pValue) );
2344
0
        }
2345
2346
0
    }
2347
0
    else if ( sType == CMIS_TYPE_BOOL )
2348
0
    {
2349
0
        Sequence<sal_Bool> seqValue;
2350
0
        rAny >>= seqValue;
2351
0
        for (const auto& rValue : seqValue)
2352
0
        {
2353
0
            std::unique_ptr<CmisYesNo> pYesNo(new CmisYesNo(m_xBox.get(), rValue));
2354
0
            pYesNo->m_xYesButton->set_sensitive( bUpdatable );
2355
0
            pYesNo->m_xNoButton->set_sensitive( bUpdatable );
2356
0
            pNewLine->m_aYesNos.push_back( std::move(pYesNo) );
2357
0
        }
2358
0
    }
2359
0
    else if ( sType == CMIS_TYPE_STRING )
2360
0
    {
2361
0
        Sequence< OUString > seqValue;
2362
0
        rAny >>= seqValue;
2363
0
        for (const auto& rValue : seqValue)
2364
0
        {
2365
0
            std::unique_ptr<CmisValue> pValue(new CmisValue(m_xBox.get(), rValue));
2366
0
            pValue->m_xValueEdit->set_editable(bUpdatable);
2367
0
            pNewLine->m_aValues.push_back( std::move(pValue) );
2368
0
        }
2369
0
    }
2370
0
    else if ( sType == CMIS_TYPE_DATETIME )
2371
0
    {
2372
0
        Sequence< util::DateTime > seqValue;
2373
0
        rAny >>= seqValue;
2374
0
        for (const auto& rValue : seqValue)
2375
0
        {
2376
0
            std::unique_ptr<CmisDateTime> pDateTime(new CmisDateTime(m_xBox.get(), rValue));
2377
0
            pDateTime->m_xDateField->set_sensitive(bUpdatable);
2378
0
            pDateTime->m_xTimeField->set_sensitive(bUpdatable);
2379
0
            pNewLine->m_aDateTimes.push_back( std::move(pDateTime) );
2380
0
        }
2381
0
    }
2382
0
    pNewLine->m_xName->set_label( sName );
2383
0
    pNewLine->m_xName->show();
2384
0
    pNewLine->m_xType->set_label( sType );
2385
0
    pNewLine->m_xType->show();
2386
2387
0
    m_aCmisPropertiesLines.push_back( std::move(pNewLine) );
2388
0
}
2389
2390
Sequence< document::CmisProperty > CmisPropertiesWindow::GetCmisProperties() const
2391
0
{
2392
0
    Sequence< document::CmisProperty > aPropertiesSeq( m_aCmisPropertiesLines.size() );
2393
0
    auto aPropertiesSeqRange = asNonConstRange(aPropertiesSeq);
2394
0
    sal_Int32 i = 0;
2395
0
    for ( auto& rxLine : m_aCmisPropertiesLines )
2396
0
    {
2397
0
        CmisPropertyLine* pLine = rxLine.get();
2398
2399
0
        aPropertiesSeqRange[i].Id = pLine->m_sId;
2400
0
        aPropertiesSeqRange[i].Type = pLine->m_sType;
2401
0
        aPropertiesSeqRange[i].Updatable = pLine->m_bUpdatable;
2402
0
        aPropertiesSeqRange[i].Required = pLine->m_bRequired;
2403
0
        aPropertiesSeqRange[i].OpenChoice = pLine->m_bOpenChoice;
2404
0
        aPropertiesSeqRange[i].MultiValued = pLine->m_bMultiValued;
2405
2406
0
        OUString sPropertyName = pLine->m_xName->get_label();
2407
0
        if ( !sPropertyName.isEmpty() )
2408
0
        {
2409
0
            aPropertiesSeqRange[i].Name = sPropertyName;
2410
0
            OUString sType = pLine->m_xType->get_label();
2411
0
            if ( CMIS_TYPE_DECIMAL == sType )
2412
0
            {
2413
0
                sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2414
0
                    m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2415
0
                Sequence< double > seqValue( pLine->m_aValues.size( ) );
2416
0
                auto seqValueRange = asNonConstRange(seqValue);
2417
0
                sal_Int32 k = 0;
2418
0
                for ( const auto& rxValue : pLine->m_aValues )
2419
0
                {
2420
0
                    double dValue = 0.0;
2421
0
                    OUString sValue( rxValue->m_xValueEdit->get_text() );
2422
0
                    bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2423
0
                    IsNumberFormat( sValue, nIndex, dValue );
2424
0
                    if ( bIsNum )
2425
0
                        seqValueRange[k] = dValue;
2426
0
                    ++k;
2427
0
                }
2428
0
                aPropertiesSeqRange[i].Value <<= seqValue;
2429
0
            }
2430
0
            else if ( CMIS_TYPE_INTEGER == sType )
2431
0
            {
2432
0
                sal_uInt32 nIndex = const_cast< SvNumberFormatter& >(
2433
0
                    m_aNumberFormatter ).GetFormatIndex( NF_NUMBER_SYSTEM );
2434
0
                Sequence< sal_Int64 > seqValue( pLine->m_aValues.size( ) );
2435
0
                auto seqValueRange = asNonConstRange(seqValue);
2436
0
                sal_Int32 k = 0;
2437
0
                for ( const auto& rxValue : pLine->m_aValues )
2438
0
                {
2439
0
                    double dValue = 0;
2440
0
                    OUString sValue( rxValue->m_xValueEdit->get_text() );
2441
0
                    bool bIsNum = const_cast< SvNumberFormatter& >( m_aNumberFormatter ).
2442
0
                    IsNumberFormat( sValue, nIndex, dValue );
2443
0
                    if ( bIsNum )
2444
0
                        seqValueRange[k] = static_cast<sal_Int64>(dValue);
2445
0
                    ++k;
2446
0
                }
2447
0
                aPropertiesSeqRange[i].Value <<= seqValue;
2448
0
            }
2449
0
            else if ( CMIS_TYPE_BOOL == sType )
2450
0
            {
2451
0
                Sequence<sal_Bool> seqValue( pLine->m_aYesNos.size( ) );
2452
0
                sal_Bool* pseqValue = seqValue.getArray();
2453
0
                sal_Int32 k = 0;
2454
0
                for ( const auto& rxYesNo : pLine->m_aYesNos )
2455
0
                {
2456
0
                    bool bValue = rxYesNo->m_xYesButton->get_active();
2457
0
                    pseqValue[k] = bValue;
2458
0
                    ++k;
2459
0
                }
2460
0
                aPropertiesSeqRange[i].Value <<= seqValue;
2461
2462
0
            }
2463
0
            else if ( CMIS_TYPE_DATETIME == sType )
2464
0
            {
2465
0
                Sequence< util::DateTime > seqValue( pLine->m_aDateTimes.size( ) );
2466
0
                auto seqValueRange = asNonConstRange(seqValue);
2467
0
                sal_Int32 k = 0;
2468
0
                for ( const auto& rxDateTime : pLine->m_aDateTimes )
2469
0
                {
2470
0
                    Date aTmpDate = rxDateTime->m_xDateField->get_date();
2471
0
                    tools::Time aTmpTime = rxDateTime->m_xFormatter->GetTime();
2472
0
                    util::DateTime aDateTime( aTmpTime.GetNanoSec(), aTmpTime.GetSec(),
2473
0
                                              aTmpTime.GetMin(), aTmpTime.GetHour(),
2474
0
                                              aTmpDate.GetDay(), aTmpDate.GetMonth(),
2475
0
                                              aTmpDate.GetYear(), true );
2476
0
                    seqValueRange[k] = aDateTime;
2477
0
                    ++k;
2478
0
                }
2479
0
                aPropertiesSeqRange[i].Value <<= seqValue;
2480
0
            }
2481
0
            else
2482
0
            {
2483
0
                Sequence< OUString > seqValue( pLine->m_aValues.size( ) );
2484
0
                auto seqValueRange = asNonConstRange(seqValue);
2485
0
                sal_Int32 k = 0;
2486
0
                for ( const auto& rxValue : pLine->m_aValues )
2487
0
                {
2488
0
                    seqValueRange[k] = rxValue->m_xValueEdit->get_text();
2489
0
                    ++k;
2490
0
                }
2491
0
                aPropertiesSeqRange[i].Value <<= seqValue;
2492
0
            }
2493
0
        }
2494
0
        ++i;
2495
0
    }
2496
2497
0
    return aPropertiesSeq;
2498
0
}
2499
2500
CmisPropertiesControl::CmisPropertiesControl(weld::Builder& rBuilder)
2501
0
    : m_aPropertiesWin(rBuilder.weld_container(u"CmisWindow"_ustr))
2502
0
    , m_xScrolledWindow(rBuilder.weld_scrolled_window(u"CmisScroll"_ustr))
2503
0
{
2504
    // set height to something small and force it to take the size
2505
    // dictated by the other pages
2506
0
    m_xScrolledWindow->set_size_request(-1, 42);
2507
0
}
2508
2509
void CmisPropertiesControl::ClearAllLines()
2510
0
{
2511
0
   m_aPropertiesWin.ClearAllLines();
2512
0
}
2513
2514
void CmisPropertiesControl::AddLine( const OUString& sId, const OUString& sName,
2515
                                     const OUString& sType, const bool bUpdatable,
2516
                                     const bool bRequired, const bool bMultiValued,
2517
                                     const bool bOpenChoice, Any& aChoices, Any const & rAny
2518
                                     )
2519
0
{
2520
0
    m_aPropertiesWin.AddLine( sId, sName, sType, bUpdatable, bRequired, bMultiValued,
2521
0
                               bOpenChoice, aChoices, rAny );
2522
0
}
2523
2524
// class SfxCmisPropertiesPage -----------------------------------------
2525
SfxCmisPropertiesPage::SfxCmisPropertiesPage(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet& rItemSet)
2526
0
    : SfxTabPage(pPage, pController, u"sfx/ui/cmisinfopage.ui"_ustr, u"CmisInfoPage"_ustr, &rItemSet)
2527
0
    , m_xPropertiesCtrl(new CmisPropertiesControl(*m_xBuilder))
2528
0
{
2529
0
}
2530
2531
SfxCmisPropertiesPage::~SfxCmisPropertiesPage()
2532
0
{
2533
0
    m_xPropertiesCtrl.reset();
2534
0
}
2535
2536
bool SfxCmisPropertiesPage::FillItemSet( SfxItemSet* rSet )
2537
0
{
2538
0
    const SfxDocumentInfoItem* pItem = nullptr;
2539
0
    SfxDocumentInfoItem* pInfo = nullptr;
2540
0
    bool bMustDelete = false;
2541
2542
0
    if (const SfxItemSet* pItemSet = GetDialogExampleSet())
2543
0
    {
2544
0
        pItem = pItemSet->GetItemIfSet(SID_DOCINFO);
2545
0
        if (!pItem)
2546
0
            pInfo = const_cast<SfxDocumentInfoItem*>(&rSet->Get( SID_DOCINFO ));
2547
0
        else
2548
0
        {
2549
0
            bMustDelete = true;
2550
0
            pInfo = new SfxDocumentInfoItem( *pItem );
2551
0
        }
2552
0
    }
2553
2554
0
    sal_Int32 modifiedNum = 0;
2555
0
    if ( pInfo )
2556
0
    {
2557
0
        Sequence< document::CmisProperty > aOldProps = pInfo->GetCmisProperties( );
2558
0
        Sequence< document::CmisProperty > aNewProps = m_xPropertiesCtrl->GetCmisProperties();
2559
2560
0
        std::vector< document::CmisProperty > changedProps;
2561
0
        for ( sal_Int32 i = 0; i< aNewProps.getLength( ); ++i )
2562
0
        {
2563
0
            if ( aOldProps[i].Updatable && !aNewProps[i].Id.isEmpty( ) )
2564
0
            {
2565
0
                if ( aOldProps[i].Type == CMIS_TYPE_DATETIME )
2566
0
                {
2567
0
                    Sequence< util::DateTime > oldValue;
2568
0
                    aOldProps[i].Value >>= oldValue;
2569
                    // We only edit hours and minutes
2570
                    // don't compare NanoSeconds and Seconds
2571
0
                    for ( auto& rDateTime : asNonConstRange(oldValue) )
2572
0
                    {
2573
0
                        rDateTime.NanoSeconds = 0;
2574
0
                        rDateTime.Seconds = 0;
2575
0
                    }
2576
0
                    Sequence< util::DateTime > newValue;
2577
0
                    aNewProps[i].Value >>= newValue;
2578
0
                    if ( oldValue != newValue )
2579
0
                    {
2580
0
                        modifiedNum++;
2581
0
                        changedProps.push_back( aNewProps[i] );
2582
0
                    }
2583
0
                }
2584
0
                else if ( aOldProps[i].Value != aNewProps[i].Value )
2585
0
                {
2586
0
                    modifiedNum++;
2587
0
                    changedProps.push_back( aNewProps[i] );
2588
0
                }
2589
0
            }
2590
0
        }
2591
0
        Sequence< document::CmisProperty> aModifiedProps( comphelper::containerToSequence(changedProps) );
2592
0
        pInfo->SetCmisProperties( aModifiedProps );
2593
0
        rSet->Put( *pInfo );
2594
0
        if ( bMustDelete )
2595
0
            delete pInfo;
2596
0
    }
2597
2598
0
    return modifiedNum;
2599
0
}
2600
2601
void SfxCmisPropertiesPage::Reset( const SfxItemSet* rItemSet )
2602
0
{
2603
0
    m_xPropertiesCtrl->ClearAllLines();
2604
0
    const SfxDocumentInfoItem& rInfoItem = rItemSet->Get(SID_DOCINFO);
2605
0
    uno::Sequence< document::CmisProperty > aCmisProps = rInfoItem.GetCmisProperties();
2606
0
    for ( auto& rCmisProp : asNonConstRange(aCmisProps) )
2607
0
    {
2608
0
        m_xPropertiesCtrl->AddLine(rCmisProp.Id,
2609
0
                                   rCmisProp.Name,
2610
0
                                   rCmisProp.Type,
2611
0
                                   rCmisProp.Updatable,
2612
0
                                   rCmisProp.Required,
2613
0
                                   rCmisProp.MultiValued,
2614
0
                                   rCmisProp.OpenChoice,
2615
0
                                   rCmisProp.Choices,
2616
0
                                   rCmisProp.Value);
2617
0
    }
2618
0
}
2619
2620
DeactivateRC SfxCmisPropertiesPage::DeactivatePage( SfxItemSet* /*pSet*/ )
2621
0
{
2622
0
    return DeactivateRC::LeavePage;
2623
0
}
2624
2625
std::unique_ptr<SfxTabPage> SfxCmisPropertiesPage::Create(weld::Container* pPage, weld::DialogController* pController, const SfxItemSet* rItemSet)
2626
0
{
2627
0
    return std::make_unique<SfxCmisPropertiesPage>(pPage, pController, *rItemSet);
2628
0
}
2629
2630
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */