Line data Source code
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 : #include "dp_gui_updatedata.hxx"
22 :
23 : #include <sal/config.h>
24 : #include <osl/file.hxx>
25 : #include <osl/conditn.hxx>
26 : #include <cppuhelper/exc_hlp.hxx>
27 : #include <tools/resid.hxx>
28 : #include <vcl/dialog.hxx>
29 : #include <vcl/msgbox.hxx>
30 : #include <vcl/svapp.hxx>
31 : #include <osl/mutex.hxx>
32 : #include <cppuhelper/implbase3.hxx>
33 :
34 : #include <com/sun/star/beans/PropertyValue.hpp>
35 : #include <com/sun/star/beans/NamedValue.hpp>
36 : #include <com/sun/star/xml/dom/XElement.hpp>
37 : #include <com/sun/star/xml/dom/XNode.hpp>
38 : #include <com/sun/star/xml/dom/XNodeList.hpp>
39 : #include <com/sun/star/ucb/NameClash.hpp>
40 : #include <com/sun/star/ucb/InteractiveAugmentedIOException.hpp>
41 : #include <com/sun/star/ucb/XCommandEnvironment.hpp>
42 : #include <com/sun/star/ucb/XProgressHandler.hpp>
43 : #include <com/sun/star/deployment/XExtensionManager.hpp>
44 : #include <com/sun/star/deployment/ExtensionManager.hpp>
45 : #include <com/sun/star/deployment/XUpdateInformationProvider.hpp>
46 : #include <com/sun/star/deployment/DependencyException.hpp>
47 : #include <com/sun/star/deployment/LicenseException.hpp>
48 : #include <com/sun/star/deployment/VersionException.hpp>
49 : #include <com/sun/star/deployment/ui/LicenseDialog.hpp>
50 : #include <com/sun/star/task/XInteractionHandler.hpp>
51 : #include <com/sun/star/ui/dialogs/XExecutableDialog.hpp>
52 : #include <com/sun/star/ui/dialogs/ExecutableDialogResults.hpp>
53 : #include <com/sun/star/task/XInteractionAbort.hpp>
54 : #include <com/sun/star/task/XInteractionApprove.hpp>
55 :
56 : #include "dp_descriptioninfoset.hxx"
57 : #include "dp_gui.hrc"
58 : #include "dp_gui_updateinstalldialog.hxx"
59 : #include "dp_gui_shared.hxx"
60 : #include "dp_ucb.h"
61 : #include "dp_misc.h"
62 : #include "dp_version.hxx"
63 : #include "dp_gui_extensioncmdqueue.hxx"
64 : #include <ucbhelper/content.hxx>
65 : #include <rtl/ref.hxx>
66 : #include <salhelper/thread.hxx>
67 : #include <com/sun/star/uno/Sequence.h>
68 : #include <comphelper/anytostring.hxx>
69 : #include <toolkit/helper/vclunohelper.hxx>
70 :
71 : #include <vector>
72 :
73 : namespace vcl { class Window; }
74 :
75 : namespace cssu = ::com::sun::star::uno;
76 :
77 : using dp_misc::StrTitle;
78 :
79 : namespace dp_gui {
80 :
81 : class UpdateInstallDialog::Thread: public salhelper::Thread {
82 : friend class UpdateCommandEnv;
83 : public:
84 : Thread(cssu::Reference< cssu::XComponentContext > ctx,
85 : UpdateInstallDialog & dialog, std::vector< dp_gui::UpdateData > & aVecUpdateData);
86 :
87 : void stop();
88 :
89 : private:
90 : virtual ~Thread();
91 :
92 : virtual void execute() SAL_OVERRIDE;
93 : void downloadExtensions();
94 : void download(OUString const & aUrls, UpdateData & aUpdatData);
95 : void installExtensions();
96 : void removeTempDownloads();
97 :
98 : UpdateInstallDialog & m_dialog;
99 : cssu::Reference< css::deployment::XUpdateInformationProvider >
100 : m_updateInformation;
101 :
102 : // guarded by Application::GetSolarMutex():
103 : cssu::Reference< css::task::XAbortChannel > m_abort;
104 : cssu::Reference< cssu::XComponentContext > m_xComponentContext;
105 : std::vector< dp_gui::UpdateData > & m_aVecUpdateData;
106 : ::rtl::Reference<UpdateCommandEnv> m_updateCmdEnv;
107 :
108 : //A folder which is created in the temp directory in which then the updates are downloaded
109 : OUString m_sDownloadFolder;
110 :
111 : bool m_stop;
112 :
113 : };
114 :
115 : class UpdateCommandEnv
116 : : public ::cppu::WeakImplHelper3< css::ucb::XCommandEnvironment,
117 : css::task::XInteractionHandler,
118 : css::ucb::XProgressHandler >
119 : {
120 : friend class UpdateInstallDialog::Thread;
121 :
122 : ::rtl::Reference<UpdateInstallDialog::Thread> m_installThread;
123 : cssu::Reference< cssu::XComponentContext > m_xContext;
124 :
125 : public:
126 : virtual ~UpdateCommandEnv();
127 : UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
128 : ::rtl::Reference<UpdateInstallDialog::Thread>const & thread);
129 :
130 : // XCommandEnvironment
131 : virtual cssu::Reference<css::task::XInteractionHandler > SAL_CALL
132 : getInteractionHandler() throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
133 : virtual cssu::Reference<css::ucb::XProgressHandler >
134 : SAL_CALL getProgressHandler() throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
135 :
136 : // XInteractionHandler
137 : virtual void SAL_CALL handle(
138 : cssu::Reference<css::task::XInteractionRequest > const & xRequest )
139 : throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
140 :
141 : // XProgressHandler
142 : virtual void SAL_CALL push( cssu::Any const & Status )
143 : throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
144 : virtual void SAL_CALL update( cssu::Any const & Status )
145 : throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
146 : virtual void SAL_CALL pop() throw (cssu::RuntimeException, std::exception) SAL_OVERRIDE;
147 : };
148 :
149 :
150 0 : UpdateInstallDialog::Thread::Thread(
151 : cssu::Reference< cssu::XComponentContext> xCtx,
152 : UpdateInstallDialog & dialog,
153 : std::vector< dp_gui::UpdateData > & aVecUpdateData):
154 : salhelper::Thread("dp_gui_updateinstalldialog"),
155 : m_dialog(dialog),
156 : m_xComponentContext(xCtx),
157 : m_aVecUpdateData(aVecUpdateData),
158 0 : m_updateCmdEnv(new UpdateCommandEnv(xCtx, this)),
159 0 : m_stop(false)
160 0 : {}
161 :
162 0 : void UpdateInstallDialog::Thread::stop() {
163 0 : cssu::Reference< css::task::XAbortChannel > abort;
164 : {
165 0 : SolarMutexGuard g;
166 0 : abort = m_abort;
167 0 : m_stop = true;
168 : }
169 0 : if (abort.is()) {
170 0 : abort->sendAbort();
171 0 : }
172 0 : }
173 :
174 0 : UpdateInstallDialog::Thread::~Thread() {}
175 :
176 0 : void UpdateInstallDialog::Thread::execute()
177 : {
178 : try {
179 0 : downloadExtensions();
180 0 : installExtensions();
181 : }
182 0 : catch (...)
183 : {
184 : }
185 :
186 : //clean up the temp directories
187 : try {
188 0 : removeTempDownloads();
189 0 : } catch( ... ) {
190 : }
191 :
192 : {
193 : //make sure m_dialog is still alive
194 0 : SolarMutexGuard g;
195 0 : if (! m_stop)
196 0 : m_dialog.updateDone();
197 : }
198 : //UpdateCommandEnv keeps a reference to Thread and prevents destruction. Therefore remove it.
199 0 : m_updateCmdEnv->m_installThread.clear();
200 0 : }
201 :
202 0 : UpdateInstallDialog::UpdateInstallDialog(
203 : vcl::Window * parent,
204 : std::vector<dp_gui::UpdateData> & aVecUpdateData,
205 : cssu::Reference< cssu::XComponentContext > const & xCtx):
206 : ModalDialog(
207 : parent,
208 : "UpdateInstallDialog","desktop/ui/updateinstalldialog.ui"),
209 :
210 0 : m_thread(new Thread(xCtx, *this, aVecUpdateData)),
211 : m_xComponentContext(xCtx),
212 : m_bError(false),
213 : m_bNoEntry(true),
214 : m_sInstalling(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_INSTALLING)),
215 : m_sFinished(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_FINISHED)),
216 : m_sNoErrors(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_NO_ERRORS)),
217 : m_sErrorDownload(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD)),
218 : m_sErrorInstallation(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION)),
219 : m_sErrorLicenseDeclined(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED)),
220 : m_sNoInstall(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL)),
221 0 : m_sThisErrorOccurred(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED))
222 : {
223 0 : get(m_pFt_action, "DOWNLOADING");
224 0 : get(m_pStatusbar, "STATUSBAR");
225 0 : get(m_pFt_extension_name, "EXTENSION_NAME");
226 0 : get(m_pMle_info, "INFO");
227 0 : m_pMle_info->set_height_request(m_pMle_info->GetTextHeight() * 5);
228 0 : m_pMle_info->set_width_request(m_pMle_info->approximate_char_width() * 56);
229 0 : get(m_pHelp, "HELP");
230 0 : get(m_pOk, "OK");
231 0 : get(m_pCancel, "CANCEL");
232 :
233 0 : m_xExtensionManager = css::deployment::ExtensionManager::get( xCtx );
234 :
235 0 : m_pCancel->SetClickHdl(LINK(this, UpdateInstallDialog, cancelHandler));
236 0 : if ( ! dp_misc::office_is_running())
237 0 : m_pHelp->Disable();
238 0 : }
239 :
240 0 : UpdateInstallDialog::~UpdateInstallDialog()
241 : {
242 0 : disposeOnce();
243 0 : }
244 :
245 0 : void UpdateInstallDialog::dispose()
246 : {
247 0 : m_pFt_action.clear();
248 0 : m_pStatusbar.clear();
249 0 : m_pFt_extension_name.clear();
250 0 : m_pMle_info.clear();
251 0 : m_pHelp.clear();
252 0 : m_pOk.clear();
253 0 : m_pCancel.clear();
254 0 : ModalDialog::dispose();
255 0 : }
256 :
257 0 : bool UpdateInstallDialog::Close()
258 : {
259 0 : m_thread->stop();
260 0 : return ModalDialog::Close();
261 : }
262 :
263 0 : short UpdateInstallDialog::Execute()
264 : {
265 0 : m_thread->launch();
266 0 : return ModalDialog::Execute();
267 : }
268 :
269 : // make sure the solar mutex is locked before calling
270 0 : void UpdateInstallDialog::updateDone()
271 : {
272 0 : if (!m_bError)
273 0 : m_pMle_info->SetText(m_pMle_info->GetText() + m_sNoErrors);
274 0 : m_pOk->Enable();
275 0 : m_pOk->GrabFocus();
276 0 : m_pCancel->Disable();
277 0 : }
278 : // make sure the solar mutex is locked before calling
279 : //sets an error message in the text area
280 0 : void UpdateInstallDialog::setError(INSTALL_ERROR err, OUString const & sExtension,
281 : OUString const & exceptionMessage)
282 : {
283 0 : OUString sError;
284 0 : m_bError = true;
285 :
286 0 : switch (err)
287 : {
288 : case ERROR_DOWNLOAD:
289 0 : sError = m_sErrorDownload;
290 0 : break;
291 : case ERROR_INSTALLATION:
292 0 : sError = m_sErrorInstallation;
293 0 : break;
294 : case ERROR_LICENSE_DECLINED:
295 0 : sError = m_sErrorLicenseDeclined;
296 0 : break;
297 :
298 : default:
299 : OSL_ASSERT(false);
300 : }
301 :
302 0 : OUString sMsg(m_pMle_info->GetText());
303 0 : sError = sError.replaceFirst("%NAME", sExtension);
304 : //We want to have an empty line between the error messages. However,
305 : //there shall be no empty line after the last entry.
306 0 : if (m_bNoEntry)
307 0 : m_bNoEntry = false;
308 : else
309 0 : sMsg += "\n";
310 0 : sMsg += sError;
311 : //Insert more information about the error
312 0 : if (!exceptionMessage.isEmpty())
313 0 : sMsg += m_sThisErrorOccurred + exceptionMessage + "\n";
314 :
315 0 : sMsg += m_sNoInstall + "\n";
316 :
317 0 : m_pMle_info->SetText(sMsg);
318 0 : }
319 :
320 0 : void UpdateInstallDialog::setError(OUString const & exceptionMessage)
321 : {
322 0 : m_bError = true;
323 0 : m_pMle_info->SetText(m_pMle_info->GetText() + exceptionMessage + "\n");
324 0 : }
325 :
326 0 : IMPL_LINK_NOARG(UpdateInstallDialog, cancelHandler)
327 : {
328 0 : m_thread->stop();
329 0 : EndDialog(RET_CANCEL);
330 0 : return 0;
331 : }
332 :
333 0 : void UpdateInstallDialog::Thread::downloadExtensions()
334 : {
335 : try
336 : {
337 : //create the download directory in the temp folder
338 0 : OUString sTempDir;
339 0 : if (::osl::FileBase::getTempDirURL(sTempDir) != ::osl::FileBase::E_None)
340 0 : throw cssu::Exception("Could not get URL for the temp directory. No extensions will be installed.", 0);
341 :
342 : //create a unique name for the directory
343 0 : OUString tempEntry, destFolder;
344 0 : if (::osl::File::createTempFile(&sTempDir, 0, &tempEntry ) != ::osl::File::E_None)
345 0 : throw cssu::Exception("Could not create a temporary file in " + sTempDir +
346 0 : ". No extensions will be installed", 0 );
347 :
348 0 : tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
349 :
350 0 : destFolder = dp_misc::makeURL( sTempDir, tempEntry );
351 0 : destFolder += "_";
352 0 : m_sDownloadFolder = destFolder;
353 : try
354 : {
355 0 : dp_misc::create_folder(0, destFolder, m_updateCmdEnv.get(), true );
356 0 : } catch (const cssu::Exception & e)
357 : {
358 0 : throw cssu::Exception(e.Message + " No extensions will be installed.", 0);
359 : }
360 :
361 :
362 0 : sal_uInt16 count = 0;
363 : typedef std::vector<UpdateData>::iterator It;
364 0 : for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i)
365 : {
366 0 : UpdateData & curData = *i;
367 :
368 0 : if (!curData.aUpdateInfo.is() || curData.aUpdateSource.is())
369 0 : continue;
370 : //We assume that m_aVecUpdateData contains only information about extensions which
371 : //can be downloaded directly.
372 : OSL_ASSERT(curData.sWebsiteURL.isEmpty());
373 :
374 : //update the name of the extension which is to be downloaded
375 : {
376 0 : SolarMutexGuard g;
377 0 : if (m_stop) {
378 0 : return;
379 : }
380 0 : m_dialog.m_pFt_extension_name->SetText(curData.aInstalledPackage->getDisplayName());
381 0 : sal_uInt16 prog = (sal::static_int_cast<sal_uInt16>(100) * ++count) /
382 0 : sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size());
383 0 : m_dialog.m_pStatusbar->SetValue(prog);
384 : }
385 0 : dp_misc::DescriptionInfoset info(m_xComponentContext, curData.aUpdateInfo);
386 : //remember occurring exceptions in case we need to print out error information
387 0 : ::std::vector< ::std::pair<OUString, cssu::Exception> > vecExceptions;
388 0 : cssu::Sequence<OUString> seqDownloadURLs = info.getUpdateDownloadUrls();
389 : OSL_ENSURE(seqDownloadURLs.getLength() > 0, "No download URL provided!");
390 0 : for (sal_Int32 j = 0; j < seqDownloadURLs.getLength(); j++)
391 : {
392 : try
393 : {
394 : OSL_ENSURE(!seqDownloadURLs[j].isEmpty(), "Download URL is empty!");
395 0 : download(seqDownloadURLs[j], curData);
396 0 : if (!curData.sLocalURL.isEmpty())
397 0 : break;
398 : }
399 0 : catch ( cssu::Exception & e )
400 : {
401 0 : vecExceptions.push_back( ::std::make_pair(seqDownloadURLs[j], e));
402 : //There can be several different errors, for example, the URL is wrong, webserver cannot be reached,
403 : //name cannot be resolved. The UCB helper API does not specify different special exceptions for these
404 : //cases. Therefore ignore and continue.
405 0 : continue;
406 : }
407 : }
408 : //update the progress and display download error
409 : {
410 0 : SolarMutexGuard g;
411 0 : if (m_stop) {
412 0 : return;
413 : }
414 0 : if (curData.sLocalURL.isEmpty())
415 : {
416 : //Construct a string of all messages contained in the exceptions plus the respective download URLs
417 0 : OUStringBuffer buf(256);
418 : typedef ::std::vector< ::std::pair<OUString, cssu::Exception > >::const_iterator CIT;
419 0 : for (CIT j = vecExceptions.begin(); j != vecExceptions.end(); ++j)
420 : {
421 0 : if (j != vecExceptions.begin())
422 0 : buf.appendAscii("\n");
423 0 : buf.append("Could not download ");
424 0 : buf.append(j->first);
425 0 : buf.appendAscii(". ");
426 0 : buf.append(j->second.Message);
427 : }
428 0 : m_dialog.setError(UpdateInstallDialog::ERROR_DOWNLOAD, curData.aInstalledPackage->getDisplayName(),
429 0 : buf.makeStringAndClear());
430 0 : }
431 : }
432 :
433 0 : }
434 : }
435 0 : catch (const cssu::Exception & e)
436 : {
437 0 : SolarMutexGuard g;
438 0 : if (m_stop) {
439 0 : return;
440 : }
441 0 : m_dialog.setError(e.Message);
442 0 : }
443 : }
444 :
445 0 : void UpdateInstallDialog::Thread::installExtensions()
446 : {
447 : //Update the fix text in the dialog to "Installing extensions..."
448 : {
449 0 : SolarMutexGuard g;
450 0 : if (m_stop) {
451 0 : return;
452 : }
453 0 : m_dialog.m_pFt_action->SetText(m_dialog.m_sInstalling);
454 0 : m_dialog.m_pStatusbar->SetValue(0);
455 : }
456 :
457 0 : sal_uInt16 count = 0;
458 : typedef std::vector<UpdateData>::iterator It;
459 0 : for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i, ++count)
460 : {
461 : //update the name of the extension which is to be installed
462 : {
463 0 : SolarMutexGuard g;
464 0 : if (m_stop) {
465 0 : return;
466 : }
467 : //we only show progress after an extension has been installed.
468 0 : if (count > 0) {
469 : m_dialog.m_pStatusbar->SetValue(
470 0 : (sal::static_int_cast<sal_uInt16>(100) * count) /
471 0 : sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size()));
472 : }
473 0 : m_dialog.m_pFt_extension_name->SetText(i->aInstalledPackage->getDisplayName());
474 : }
475 0 : bool bError = false;
476 0 : bool bLicenseDeclined = false;
477 0 : cssu::Reference<css::deployment::XPackage> xExtension;
478 0 : UpdateData & curData = *i;
479 0 : cssu::Exception exc;
480 : try
481 : {
482 : cssu::Reference< css::task::XAbortChannel > xAbortChannel(
483 0 : curData.aInstalledPackage->createAbortChannel() );
484 : {
485 0 : SolarMutexGuard g;
486 0 : if (m_stop) {
487 0 : return;
488 : }
489 0 : m_abort = xAbortChannel;
490 : }
491 0 : if (!curData.aUpdateSource.is() && !curData.sLocalURL.isEmpty())
492 : {
493 0 : css::beans::NamedValue prop("EXTENSION_UPDATE", css::uno::makeAny(OUString("1")));
494 0 : if (!curData.bIsShared)
495 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
496 : curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
497 0 : "user", xAbortChannel, m_updateCmdEnv.get());
498 : else
499 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
500 : curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
501 0 : "shared", xAbortChannel, m_updateCmdEnv.get());
502 : }
503 0 : else if (curData.aUpdateSource.is())
504 : {
505 : OSL_ASSERT(curData.aUpdateSource.is());
506 : //I am not sure if we should obtain the install properties and pass them into
507 : //add extension. Currently it contains only "SUPPRESS_LICENSE". So it could happen
508 : //that a license is displayed when updating from the shared repository, although the
509 : //shared extension was installed using "SUPPRESS_LICENSE".
510 0 : css::beans::NamedValue prop("EXTENSION_UPDATE", css::uno::makeAny(OUString("1")));
511 0 : if (!curData.bIsShared)
512 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
513 0 : curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
514 0 : "user", xAbortChannel, m_updateCmdEnv.get());
515 : else
516 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
517 0 : curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
518 0 : "shared", xAbortChannel, m_updateCmdEnv.get());
519 0 : }
520 : }
521 0 : catch (css::deployment::DeploymentException & de)
522 : {
523 0 : if (de.Cause.has<css::deployment::LicenseException>())
524 : {
525 0 : bLicenseDeclined = true;
526 : }
527 : else
528 : {
529 0 : exc = de.Cause.get<cssu::Exception>();
530 0 : bError = true;
531 : }
532 : }
533 0 : catch (cssu::Exception& e)
534 : {
535 0 : exc = e;
536 0 : bError = true;
537 : }
538 :
539 0 : if (bLicenseDeclined)
540 : {
541 0 : SolarMutexGuard g;
542 0 : if (m_stop) {
543 0 : return;
544 : }
545 : m_dialog.setError(UpdateInstallDialog::ERROR_LICENSE_DECLINED,
546 0 : curData.aInstalledPackage->getDisplayName(), OUString());
547 : }
548 0 : else if (!xExtension.is() || bError)
549 : {
550 0 : SolarMutexGuard g;
551 0 : if (m_stop) {
552 0 : return;
553 : }
554 : m_dialog.setError(UpdateInstallDialog::ERROR_INSTALLATION,
555 0 : curData.aInstalledPackage->getDisplayName(), exc.Message);
556 : }
557 0 : }
558 : {
559 0 : SolarMutexGuard g;
560 0 : if (m_stop) {
561 0 : return;
562 : }
563 0 : m_dialog.m_pStatusbar->SetValue(100);
564 0 : m_dialog.m_pFt_extension_name->SetText(OUString());
565 0 : m_dialog.m_pFt_action->SetText(m_dialog.m_sFinished);
566 : }
567 : }
568 :
569 0 : void UpdateInstallDialog::Thread::removeTempDownloads()
570 : {
571 0 : if (!m_sDownloadFolder.isEmpty())
572 : {
573 : dp_misc::erase_path(m_sDownloadFolder,
574 0 : cssu::Reference<css::ucb::XCommandEnvironment>(),false /* no throw: ignore errors */ );
575 : //remove also the temp file which we have used to create the unique name
576 0 : OUString tempFile = m_sDownloadFolder.copy(0, m_sDownloadFolder.getLength() - 1);
577 0 : dp_misc::erase_path(tempFile, cssu::Reference<css::ucb::XCommandEnvironment>(),false);
578 0 : m_sDownloadFolder.clear();
579 : }
580 0 : }
581 :
582 0 : void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData)
583 : {
584 : {
585 0 : SolarMutexGuard g;
586 0 : if (m_stop) {
587 0 : return;
588 0 : }
589 : }
590 :
591 : OSL_ASSERT(m_sDownloadFolder.getLength());
592 0 : OUString destFolder, tempEntry;
593 0 : if (::osl::File::createTempFile(
594 : &m_sDownloadFolder,
595 0 : 0, &tempEntry ) != ::osl::File::E_None)
596 : {
597 : //ToDo feedback in window that download of this component failed
598 0 : throw cssu::Exception("Could not create temporary file in folder " + destFolder + ".", 0);
599 : }
600 0 : tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
601 :
602 0 : destFolder = dp_misc::makeURL( m_sDownloadFolder, tempEntry );
603 0 : destFolder += "_";
604 :
605 0 : ::ucbhelper::Content destFolderContent;
606 0 : dp_misc::create_folder( &destFolderContent, destFolder, m_updateCmdEnv.get() );
607 :
608 0 : ::ucbhelper::Content sourceContent;
609 0 : dp_misc::create_ucb_content( &sourceContent, sDownloadURL, m_updateCmdEnv.get() );
610 :
611 0 : const OUString sTitle( StrTitle::getTitle( sourceContent ) );
612 :
613 0 : if (destFolderContent.transferContent(
614 : sourceContent, ::ucbhelper::InsertOperation_COPY,
615 0 : sTitle, css::ucb::NameClash::OVERWRITE ))
616 : {
617 : //the user may have cancelled the dialog because downloading took to long
618 : {
619 0 : SolarMutexGuard g;
620 0 : if (m_stop) {
621 0 : return;
622 : }
623 : //all errors should be handeld by the command environment.
624 0 : aUpdateData.sLocalURL = destFolder + "/" + sTitle;
625 : }
626 0 : }
627 : }
628 :
629 0 : UpdateCommandEnv::UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
630 : ::rtl::Reference<UpdateInstallDialog::Thread>const & thread)
631 : : m_installThread(thread),
632 0 : m_xContext(xCtx)
633 : {
634 0 : }
635 :
636 0 : UpdateCommandEnv::~UpdateCommandEnv()
637 : {
638 0 : }
639 :
640 : // XCommandEnvironment
641 0 : cssu::Reference<css::task::XInteractionHandler> UpdateCommandEnv::getInteractionHandler()
642 : throw (cssu::RuntimeException, std::exception)
643 : {
644 0 : return this;
645 : }
646 :
647 0 : cssu::Reference<css::ucb::XProgressHandler> UpdateCommandEnv::getProgressHandler()
648 : throw (cssu::RuntimeException, std::exception)
649 : {
650 0 : return this;
651 : }
652 :
653 : // XInteractionHandler
654 0 : void UpdateCommandEnv::handle(
655 : cssu::Reference< css::task::XInteractionRequest> const & xRequest )
656 : throw (cssu::RuntimeException, std::exception)
657 : {
658 0 : cssu::Any request( xRequest->getRequest() );
659 : OSL_ASSERT( request.getValueTypeClass() == cssu::TypeClass_EXCEPTION );
660 : dp_misc::TRACE("[dp_gui_cmdenv.cxx] incoming request:\n"
661 0 : + ::comphelper::anyToString(request) + "\n\n");
662 :
663 0 : css::deployment::VersionException verExc;
664 0 : bool approve = false;
665 :
666 0 : if (request >>= verExc)
667 : { //We must catch the version exception during the update,
668 : //because otherwise the user would be confronted with the dialogs, asking
669 : //them if they want to replace an already installed version of the same extension.
670 : //During an update we assume that we always want to replace the old version with the
671 : //new version.
672 0 : approve = true;
673 : }
674 :
675 0 : if (!approve)
676 : {
677 : //forward to interaction handler for main dialog.
678 0 : handleInteractionRequest( m_xContext, xRequest );
679 : }
680 : else
681 : {
682 : // select:
683 : cssu::Sequence< cssu::Reference< css::task::XInteractionContinuation > > conts(
684 0 : xRequest->getContinuations() );
685 : cssu::Reference< css::task::XInteractionContinuation > const * pConts =
686 0 : conts.getConstArray();
687 0 : sal_Int32 len = conts.getLength();
688 0 : for ( sal_Int32 pos = 0; pos < len; ++pos )
689 : {
690 0 : if (approve) {
691 : cssu::Reference< css::task::XInteractionApprove > xInteractionApprove(
692 0 : pConts[ pos ], cssu::UNO_QUERY );
693 0 : if (xInteractionApprove.is()) {
694 0 : xInteractionApprove->select();
695 : // don't query again for ongoing continuations:
696 0 : approve = false;
697 0 : }
698 : }
699 0 : }
700 0 : }
701 0 : }
702 :
703 : // XProgressHandler
704 0 : void UpdateCommandEnv::push( cssu::Any const & /*Status*/ )
705 : throw (cssu::RuntimeException, std::exception)
706 : {
707 0 : }
708 :
709 0 : void UpdateCommandEnv::update( cssu::Any const & /*Status */)
710 : throw (cssu::RuntimeException, std::exception)
711 : {
712 0 : }
713 :
714 0 : void UpdateCommandEnv::pop() throw (cssu::RuntimeException, std::exception)
715 : {
716 0 : }
717 :
718 :
719 3 : } //end namespace dp_gui
720 :
721 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|