Coverage Report

Created: 2026-03-31 11:00

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sfx2/source/appl/impldde.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
21
#if defined(_WIN32)
22
#include <prewin.h>
23
#include <postwin.h>
24
#endif
25
26
#include "impldde.hxx"
27
28
#include <vcl/vclenum.hxx>
29
#include <vcl/weld/Builder.hxx>
30
#include <vcl/weld/DialogController.hxx>
31
#include <vcl/weld/Entry.hxx>
32
#include <vcl/weld/weld.hxx>
33
#include <sot/exchange.hxx>
34
#include <rtl/ustring.hxx>
35
36
#include <sfx2/lnkbase.hxx>
37
#include <sfx2/linkmgr.hxx>
38
39
#include <com/sun/star/uno/Any.hxx>
40
#include <com/sun/star/uno/Sequence.hxx>
41
42
#include <svl/svdde.hxx>
43
#include <sot/formats.hxx>
44
45
using namespace ::com::sun::star::uno;
46
47
namespace sfx2
48
{
49
50
namespace {
51
52
class SvDDELinkEditDialog : public weld::GenericDialogController
53
{
54
    std::unique_ptr<weld::Entry> m_xEdDdeApp;
55
    std::unique_ptr<weld::Entry> m_xEdDdeTopic;
56
    std::unique_ptr<weld::Entry> m_xEdDdeItem;
57
    std::unique_ptr<weld::Button> m_xOKButton;
58
59
    DECL_LINK(EditHdl_Impl, weld::Entry&, void);
60
public:
61
    SvDDELinkEditDialog(weld::Window* pParent, SvBaseLink const*);
62
    OUString GetCmd() const;
63
};
64
65
}
66
67
SvDDELinkEditDialog::SvDDELinkEditDialog(weld::Window* pParent, SvBaseLink const * pLink)
68
0
    : GenericDialogController(pParent, u"sfx/ui/linkeditdialog.ui"_ustr, u"LinkEditDialog"_ustr)
69
0
    , m_xEdDdeApp(m_xBuilder->weld_entry(u"app"_ustr))
70
0
    , m_xEdDdeTopic(m_xBuilder->weld_entry(u"file"_ustr))
71
0
    , m_xEdDdeItem(m_xBuilder->weld_entry(u"category"_ustr))
72
0
    , m_xOKButton(m_xBuilder->weld_button(u"ok"_ustr))
73
0
{
74
0
    OUString sServer, sTopic, sItem;
75
0
    sfx2::LinkManager::GetDisplayNames( pLink, &sServer, &sTopic, &sItem );
76
77
0
    m_xEdDdeApp->set_text( sServer );
78
0
    m_xEdDdeTopic->set_text( sTopic );
79
0
    m_xEdDdeItem->set_text( sItem );
80
81
0
    m_xEdDdeApp->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
82
0
    m_xEdDdeTopic->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
83
0
    m_xEdDdeItem->connect_changed( LINK( this, SvDDELinkEditDialog, EditHdl_Impl));
84
85
0
    m_xOKButton->set_sensitive(!sServer.isEmpty() && !sTopic.isEmpty() && !sItem.isEmpty());
86
0
}
87
88
OUString SvDDELinkEditDialog::GetCmd() const
89
0
{
90
0
    OUString sCmd( m_xEdDdeApp->get_text() ), sRet;
91
0
    ::sfx2::MakeLnkName( sRet, &sCmd, m_xEdDdeTopic->get_text(), m_xEdDdeItem->get_text() );
92
0
    return sRet;
93
0
}
94
95
IMPL_LINK_NOARG( SvDDELinkEditDialog, EditHdl_Impl, weld::Entry&, void)
96
0
{
97
0
    m_xOKButton->set_sensitive(!m_xEdDdeApp->get_text().isEmpty() &&
98
0
                               !m_xEdDdeTopic->get_text().isEmpty() &&
99
0
                               !m_xEdDdeItem->get_text().isEmpty() );
100
0
}
101
102
SvDDEObject::SvDDEObject()
103
0
    :  pGetData( nullptr )
104
0
{
105
0
    SetUpdateTimeout( 100 );
106
0
    bWaitForData = false;
107
0
}
108
109
SvDDEObject::~SvDDEObject()
110
0
{
111
0
    pLink.reset();
112
0
    pRequest.reset();
113
0
    pConnection.reset();
114
0
}
115
116
bool SvDDEObject::GetData( css::uno::Any & rData /*out param*/,
117
                            const OUString & rMimeType,
118
                            bool bSynchron )
119
0
{
120
0
    if( !pConnection )
121
0
        return false;
122
123
0
    if( pConnection->GetError() )  // then we try once more
124
0
    {
125
0
        OUString sServer( pConnection->GetServiceName() );
126
0
        OUString sTopic( pConnection->GetTopicName() );
127
128
0
        pConnection.reset( new DdeConnection( sServer, sTopic ) );
129
0
    }
130
131
0
    if( bWaitForData ) // we are in a recursive loop, get out again
132
0
        return false;
133
134
    // Lock against Reentrance
135
0
    bWaitForData = true;
136
137
    // if you want to print, we'll wait until the data is available
138
0
    if( bSynchron )
139
0
    {
140
0
        DdeRequest aReq( *pConnection, sItem, 5000 );
141
0
        aReq.SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
142
0
        aReq.SetFormat( SotExchange::GetFormatIdFromMimeType( rMimeType ));
143
144
0
        pGetData = &rData;
145
146
0
        do {
147
0
            aReq.Execute();
148
0
        } while( aReq.GetError() && ImplHasOtherFormat( aReq ) );
149
150
0
        bWaitForData = false;
151
0
    }
152
0
    else
153
0
    {
154
        // otherwise it will be executed asynchronously
155
0
        {
156
0
            pRequest.reset( new DdeRequest( *pConnection, sItem ) );
157
0
            pRequest->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
158
0
            pRequest->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
159
0
            pRequest->SetFormat( SotExchange::GetFormatIdFromMimeType(
160
0
                                    rMimeType ) );
161
0
            pRequest->Execute();
162
0
        }
163
164
0
        rData <<= OUString();
165
0
    }
166
0
    return 0 == pConnection->GetError();
167
0
}
168
169
170
bool SvDDEObject::Connect( SvBaseLink * pSvLink )
171
0
{
172
0
    SfxLinkUpdateMode nLinkType = pSvLink->GetUpdateMode();
173
0
    if( pConnection )           // Connection is already made
174
0
    {
175
        // well, then just add it as dependent
176
0
        AddDataAdvise( pSvLink,
177
0
                SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
178
0
                SfxLinkUpdateMode::ONCALL == nLinkType
179
0
                        ? ADVISEMODE_ONLYONCE
180
0
                        : 0 );
181
0
        AddConnectAdvise( pSvLink );
182
183
0
        return true;
184
0
    }
185
186
0
    if( !pSvLink->GetLinkManager() )
187
0
        return false;
188
189
0
    OUString sServer, sTopic;
190
0
    sfx2::LinkManager::GetDisplayNames( pSvLink, &sServer, &sTopic, &sItem );
191
192
0
    if( sServer.isEmpty() || sTopic.isEmpty() || sItem.isEmpty() )
193
0
        return false;
194
195
0
    pConnection.reset( new DdeConnection( sServer, sTopic ) );
196
0
    if( pConnection->GetError() )
197
0
    {
198
        // check if the DDE server knows the "SYSTEM" topic
199
0
        bool bSysTopic = false;
200
0
        if (!sTopic.equalsIgnoreAsciiCase("SYSTEM"))
201
0
        {
202
0
            DdeConnection aTmp(sServer, u"SYSTEM"_ustr);
203
0
            bSysTopic = !aTmp.GetError();
204
0
        }
205
206
0
        if( bSysTopic )
207
0
        {
208
            // if the system topic works then the server is up but just doesn't know the original topic
209
0
            return false;
210
0
        }
211
0
    }
212
213
0
    if( SfxLinkUpdateMode::ALWAYS == nLinkType && !pLink && !pConnection->GetError() )
214
0
    {
215
        // Setting up Hot Link, Data will be available at some point later on
216
0
        pLink.reset( new DdeHotLink( *pConnection, sItem ) );
217
0
        pLink->SetDataHdl( LINK( this, SvDDEObject, ImplGetDDEData ) );
218
0
        pLink->SetDoneHdl( LINK( this, SvDDEObject, ImplDoneDDEData ) );
219
0
        pLink->SetFormat( pSvLink->GetContentType() );
220
0
        pLink->Execute();
221
0
    }
222
223
0
    if( pConnection->GetError() )
224
0
        return false;
225
226
0
    AddDataAdvise( pSvLink,
227
0
                SotExchange::GetFormatMimeType( pSvLink->GetContentType()),
228
0
                SfxLinkUpdateMode::ONCALL == nLinkType
229
0
                        ? ADVISEMODE_ONLYONCE
230
0
                        : 0 );
231
0
    AddConnectAdvise( pSvLink );
232
0
    SetUpdateTimeout( 0 );
233
0
    return true;
234
0
}
235
236
void SvDDEObject::Edit(weld::Window* pParent, sfx2::SvBaseLink* pBaseLink, const Link<const OUString&, void>& rEndEditHdl)
237
0
{
238
0
    SvDDELinkEditDialog aDlg(pParent, pBaseLink);
239
0
    if (RET_OK == aDlg.run() && rEndEditHdl.IsSet())
240
0
    {
241
0
        OUString sCommand = aDlg.GetCmd();
242
0
        rEndEditHdl.Call( sCommand );
243
0
    }
244
0
}
245
246
bool SvDDEObject::ImplHasOtherFormat( DdeTransaction& rReq )
247
0
{
248
0
    SotClipboardFormatId nFmt = SotClipboardFormatId::NONE;
249
0
    switch( rReq.GetFormat() )
250
0
    {
251
0
    case SotClipboardFormatId::RTF:
252
0
        nFmt = SotClipboardFormatId::STRING;
253
0
        break;
254
255
0
    case SotClipboardFormatId::HTML_SIMPLE:
256
0
    case SotClipboardFormatId::HTML:
257
0
        nFmt = SotClipboardFormatId::RTF;
258
0
        break;
259
260
0
    case SotClipboardFormatId::GDIMETAFILE:
261
0
        nFmt = SotClipboardFormatId::BITMAP;
262
0
        break;
263
264
0
    case SotClipboardFormatId::SVXB:
265
0
        nFmt = SotClipboardFormatId::GDIMETAFILE;
266
0
        break;
267
268
    // something else?
269
0
    default: break;
270
0
    }
271
0
    if( nFmt != SotClipboardFormatId::NONE )
272
0
        rReq.SetFormat( nFmt );         // try it once more
273
0
    return SotClipboardFormatId::NONE != nFmt;
274
0
}
275
276
bool SvDDEObject::IsPending() const
277
/*
278
    The method determines whether the data-object can be read from a DDE.
279
*/
280
0
{
281
0
    return bWaitForData;
282
0
}
283
284
bool SvDDEObject::IsDataComplete() const
285
0
{
286
0
    return bWaitForData;
287
0
}
288
289
IMPL_LINK( SvDDEObject, ImplGetDDEData, const DdeData*, pData, void )
290
0
{
291
0
    SotClipboardFormatId nFmt = pData->GetFormat();
292
0
    switch( nFmt )
293
0
    {
294
0
    case SotClipboardFormatId::GDIMETAFILE:
295
0
        break;
296
297
0
    case SotClipboardFormatId::BITMAP:
298
0
        break;
299
300
0
    default:
301
0
        {
302
0
            const char* p = static_cast<char const *>(pData->getData());
303
0
            tools::Long nLen = SotClipboardFormatId::STRING == nFmt ? (p ? strlen( p ) : 0) : pData->getSize();
304
305
0
            Sequence< sal_Int8 > aSeq( reinterpret_cast<const sal_Int8*>(p), nLen );
306
0
            if( pGetData )
307
0
            {
308
0
                *pGetData <<= aSeq;  // Copy Data
309
0
                pGetData = nullptr;        // reset the pointer here
310
0
            }
311
0
            else
312
0
            {
313
0
                Any aVal;
314
0
                aVal <<= aSeq;
315
0
                DataChanged( SotExchange::GetFormatMimeType(
316
0
                                                pData->GetFormat() ), aVal );
317
0
                bWaitForData = false;
318
0
            }
319
0
        }
320
0
    }
321
0
}
322
323
IMPL_LINK( SvDDEObject, ImplDoneDDEData, bool, bValid, void )
324
0
{
325
0
    if( !bValid && ( pRequest || pLink ))
326
0
    {
327
0
        DdeTransaction* pReq = nullptr;
328
0
        if( !pLink || ( pLink && pLink->IsBusy() ))
329
0
            pReq = pRequest.get();  // only the one that is ready
330
0
        else if( pRequest && pRequest->IsBusy() )
331
0
            pReq = pLink.get();  // only the one that is ready
332
333
0
        if( pReq )
334
0
        {
335
0
            if( ImplHasOtherFormat( *pReq ) )
336
0
            {
337
0
                pReq->Execute();
338
0
            }
339
0
            else if( pReq == pRequest.get() )
340
0
            {
341
0
                bWaitForData = false;
342
0
            }
343
0
        }
344
0
    }
345
0
    else
346
        // End waiting
347
0
        bWaitForData = false;
348
0
}
349
350
}
351
352
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */