/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: */ |