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 : 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 : Window * parent,
204 : std::vector<dp_gui::UpdateData> & aVecUpdateData,
205 : cssu::Reference< cssu::XComponentContext > const & xCtx):
206 : ModalDialog(
207 : parent,
208 : DpGuiResId(RID_DLG_UPDATEINSTALL)),
209 :
210 0 : m_thread(new Thread(xCtx, *this, aVecUpdateData)),
211 : m_xComponentContext(xCtx),
212 : m_bError(false),
213 : m_bNoEntry(true),
214 : m_bActivated(false),
215 : m_sInstalling(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_INSTALLING)),
216 : m_sFinished(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_FINISHED)),
217 : m_sNoErrors(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_NO_ERRORS)),
218 : m_sErrorDownload(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_DOWNLOAD)),
219 : m_sErrorInstallation(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_INSTALLATION)),
220 : m_sErrorLicenseDeclined(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_ERROR_LIC_DECLINED)),
221 : m_sNoInstall(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_EXTENSION_NOINSTALL)),
222 : m_sThisErrorOccurred(DPGUI_RESSTR(RID_DLG_UPDATE_INSTALL_THIS_ERROR_OCCURRED)),
223 : m_ft_action(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_DOWNLOADING)),
224 : m_statusbar(this,DpGuiResId(RID_DLG_UPDATE_INSTALL_STATUSBAR)),
225 : m_ft_extension_name(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_EXTENSION_NAME)),
226 : m_ft_results(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_RESULTS)),
227 : m_mle_info(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_INFO)),
228 : m_line(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_LINE)),
229 : m_help(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_HELP)),
230 : m_ok(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_OK)),
231 0 : m_cancel(this, DpGuiResId(RID_DLG_UPDATE_INSTALL_ABORT))
232 : {
233 0 : FreeResource();
234 :
235 0 : m_xExtensionManager = css::deployment::ExtensionManager::get( xCtx );
236 :
237 0 : m_cancel.SetClickHdl(LINK(this, UpdateInstallDialog, cancelHandler));
238 0 : m_mle_info.EnableCursor(false);
239 0 : if ( ! dp_misc::office_is_running())
240 0 : m_help.Disable();
241 0 : }
242 :
243 0 : UpdateInstallDialog::~UpdateInstallDialog() {}
244 :
245 0 : bool UpdateInstallDialog::Close()
246 : {
247 0 : m_thread->stop();
248 0 : return ModalDialog::Close();
249 : }
250 :
251 0 : short UpdateInstallDialog::Execute()
252 : {
253 0 : m_thread->launch();
254 0 : return ModalDialog::Execute();
255 : }
256 :
257 : // make sure the solar mutex is locked before calling
258 0 : void UpdateInstallDialog::updateDone()
259 : {
260 0 : if (!m_bError)
261 0 : m_mle_info.InsertText(m_sNoErrors);
262 0 : m_ok.Enable();
263 0 : m_ok.GrabFocus();
264 0 : m_cancel.Disable();
265 0 : }
266 : // make sure the solar mutex is locked before calling
267 : //sets an error message in the text area
268 0 : void UpdateInstallDialog::setError(INSTALL_ERROR err, OUString const & sExtension,
269 : OUString const & exceptionMessage)
270 : {
271 0 : OUString sError;
272 0 : m_bError = true;
273 :
274 0 : switch (err)
275 : {
276 : case ERROR_DOWNLOAD:
277 0 : sError = m_sErrorDownload;
278 0 : break;
279 : case ERROR_INSTALLATION:
280 0 : sError = m_sErrorInstallation;
281 0 : break;
282 : case ERROR_LICENSE_DECLINED:
283 0 : sError = m_sErrorLicenseDeclined;
284 0 : break;
285 :
286 : default:
287 : OSL_ASSERT(false);
288 : }
289 :
290 0 : sError = sError.replaceFirst("%NAME", sExtension);
291 : //We want to have an empty line between the error messages. However,
292 : //there shall be no empty line after the last entry.
293 0 : if (m_bNoEntry)
294 0 : m_bNoEntry = false;
295 : else
296 0 : m_mle_info.InsertText(OUString("\n"));
297 0 : m_mle_info.InsertText(sError);
298 : //Insert more information about the error
299 0 : if (!exceptionMessage.isEmpty())
300 0 : m_mle_info.InsertText(m_sThisErrorOccurred + exceptionMessage + "\n");
301 :
302 0 : m_mle_info.InsertText(m_sNoInstall);
303 0 : m_mle_info.InsertText(OUString("\n"));
304 0 : }
305 :
306 0 : void UpdateInstallDialog::setError(OUString const & exceptionMessage)
307 : {
308 0 : m_bError = true;
309 0 : m_mle_info.InsertText(exceptionMessage + "\n");
310 0 : }
311 :
312 0 : IMPL_LINK_NOARG(UpdateInstallDialog, cancelHandler)
313 : {
314 0 : m_thread->stop();
315 0 : EndDialog(RET_CANCEL);
316 0 : return 0;
317 : }
318 :
319 0 : void UpdateInstallDialog::Thread::downloadExtensions()
320 : {
321 : try
322 : {
323 : //create the download directory in the temp folder
324 0 : OUString sTempDir;
325 0 : if (::osl::FileBase::getTempDirURL(sTempDir) != ::osl::FileBase::E_None)
326 0 : throw cssu::Exception("Could not get URL for the temp directory. No extensions will be installed.", 0);
327 :
328 : //create a unique name for the directory
329 0 : OUString tempEntry, destFolder;
330 0 : if (::osl::File::createTempFile(&sTempDir, 0, &tempEntry ) != ::osl::File::E_None)
331 0 : throw cssu::Exception("Could not create a temporary file in " + sTempDir +
332 0 : ". No extensions will be installed", 0 );
333 :
334 0 : tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
335 :
336 0 : destFolder = dp_misc::makeURL( sTempDir, tempEntry );
337 0 : destFolder += "_";
338 0 : m_sDownloadFolder = destFolder;
339 : try
340 : {
341 0 : dp_misc::create_folder(0, destFolder, m_updateCmdEnv.get(), true );
342 0 : } catch (const cssu::Exception & e)
343 : {
344 0 : throw cssu::Exception(e.Message + " No extensions will be installed.", 0);
345 : }
346 :
347 :
348 0 : sal_uInt16 count = 0;
349 : typedef std::vector<UpdateData>::iterator It;
350 0 : for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i)
351 : {
352 0 : UpdateData & curData = *i;
353 :
354 0 : if (!curData.aUpdateInfo.is() || curData.aUpdateSource.is())
355 0 : continue;
356 : //We assume that m_aVecUpdateData contains only information about extensions which
357 : //can be downloaded directly.
358 : OSL_ASSERT(curData.sWebsiteURL.isEmpty());
359 :
360 : //update the name of the extension which is to be downloaded
361 : {
362 0 : SolarMutexGuard g;
363 0 : if (m_stop) {
364 0 : return;
365 : }
366 0 : m_dialog.m_ft_extension_name.SetText(curData.aInstalledPackage->getDisplayName());
367 0 : sal_uInt16 prog = (sal::static_int_cast<sal_uInt16>(100) * ++count) /
368 0 : sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size());
369 0 : m_dialog.m_statusbar.SetValue(prog);
370 : }
371 0 : dp_misc::DescriptionInfoset info(m_xComponentContext, curData.aUpdateInfo);
372 : //remember occurring exceptions in case we need to print out error information
373 0 : ::std::vector< ::std::pair<OUString, cssu::Exception> > vecExceptions;
374 0 : cssu::Sequence<OUString> seqDownloadURLs = info.getUpdateDownloadUrls();
375 : OSL_ENSURE(seqDownloadURLs.getLength() > 0, "No download URL provided!");
376 0 : for (sal_Int32 j = 0; j < seqDownloadURLs.getLength(); j++)
377 : {
378 : try
379 : {
380 : OSL_ENSURE(!seqDownloadURLs[j].isEmpty(), "Download URL is empty!");
381 0 : download(seqDownloadURLs[j], curData);
382 0 : if (!curData.sLocalURL.isEmpty())
383 0 : break;
384 : }
385 0 : catch ( cssu::Exception & e )
386 : {
387 0 : vecExceptions.push_back( ::std::make_pair(seqDownloadURLs[j], e));
388 : //There can be several different errors, for example, the URL is wrong, webserver cannot be reached,
389 : //name cannot be resolved. The UCB helper API does not specify different special exceptions for these
390 : //cases. Therefore ignore and continue.
391 0 : continue;
392 : }
393 : }
394 : //update the progress and display download error
395 : {
396 0 : SolarMutexGuard g;
397 0 : if (m_stop) {
398 0 : return;
399 : }
400 0 : if (curData.sLocalURL.isEmpty())
401 : {
402 : //Construct a string of all messages contained in the exceptions plus the respective download URLs
403 0 : OUStringBuffer buf(256);
404 : typedef ::std::vector< ::std::pair<OUString, cssu::Exception > >::const_iterator CIT;
405 0 : for (CIT j = vecExceptions.begin(); j != vecExceptions.end(); ++j)
406 : {
407 0 : if (j != vecExceptions.begin())
408 0 : buf.appendAscii("\n");
409 0 : buf.append("Could not download ");
410 0 : buf.append(j->first);
411 0 : buf.appendAscii(". ");
412 0 : buf.append(j->second.Message);
413 : }
414 0 : m_dialog.setError(UpdateInstallDialog::ERROR_DOWNLOAD, curData.aInstalledPackage->getDisplayName(),
415 0 : buf.makeStringAndClear());
416 0 : }
417 : }
418 :
419 0 : }
420 : }
421 0 : catch (const cssu::Exception & e)
422 : {
423 0 : SolarMutexGuard g;
424 0 : if (m_stop) {
425 0 : return;
426 : }
427 0 : m_dialog.setError(e.Message);
428 0 : }
429 : }
430 :
431 0 : void UpdateInstallDialog::Thread::installExtensions()
432 : {
433 : //Update the fix text in the dialog to "Installing extensions..."
434 : {
435 0 : SolarMutexGuard g;
436 0 : if (m_stop) {
437 0 : return;
438 : }
439 0 : m_dialog.m_ft_action.SetText(m_dialog.m_sInstalling);
440 0 : m_dialog.m_statusbar.SetValue(0);
441 : }
442 :
443 0 : sal_uInt16 count = 0;
444 : typedef std::vector<UpdateData>::iterator It;
445 0 : for (It i = m_aVecUpdateData.begin(); i != m_aVecUpdateData.end(); ++i, ++count)
446 : {
447 : //update the name of the extension which is to be installed
448 : {
449 0 : SolarMutexGuard g;
450 0 : if (m_stop) {
451 0 : return;
452 : }
453 : //we only show progress after an extension has been installed.
454 0 : if (count > 0) {
455 : m_dialog.m_statusbar.SetValue(
456 0 : (sal::static_int_cast<sal_uInt16>(100) * count) /
457 0 : sal::static_int_cast<sal_uInt16>(m_aVecUpdateData.size()));
458 : }
459 0 : m_dialog.m_ft_extension_name.SetText(i->aInstalledPackage->getDisplayName());
460 : }
461 0 : bool bError = false;
462 0 : bool bLicenseDeclined = false;
463 0 : cssu::Reference<css::deployment::XPackage> xExtension;
464 0 : UpdateData & curData = *i;
465 0 : cssu::Exception exc;
466 : try
467 : {
468 : cssu::Reference< css::task::XAbortChannel > xAbortChannel(
469 0 : curData.aInstalledPackage->createAbortChannel() );
470 : {
471 0 : SolarMutexGuard g;
472 0 : if (m_stop) {
473 0 : return;
474 : }
475 0 : m_abort = xAbortChannel;
476 : }
477 0 : if (!curData.aUpdateSource.is() && !curData.sLocalURL.isEmpty())
478 : {
479 0 : css::beans::NamedValue prop("EXTENSION_UPDATE", css::uno::makeAny(OUString("1")));
480 0 : if (!curData.bIsShared)
481 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
482 : curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
483 0 : "user", xAbortChannel, m_updateCmdEnv.get());
484 : else
485 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
486 : curData.sLocalURL, css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
487 0 : "shared", xAbortChannel, m_updateCmdEnv.get());
488 : }
489 0 : else if (curData.aUpdateSource.is())
490 : {
491 : OSL_ASSERT(curData.aUpdateSource.is());
492 : //I am not sure if we should obtain the install properties and pass them into
493 : //add extension. Currently it contains only "SUPPRESS_LICENSE". So it it could happen
494 : //that a license is displayed when updating from the shared repository, although the
495 : //shared extension was installed using "SUPPRESS_LICENSE".
496 0 : css::beans::NamedValue prop("EXTENSION_UPDATE", css::uno::makeAny(OUString("1")));
497 0 : if (!curData.bIsShared)
498 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
499 0 : curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
500 0 : "user", xAbortChannel, m_updateCmdEnv.get());
501 : else
502 0 : xExtension = m_dialog.getExtensionManager()->addExtension(
503 0 : curData.aUpdateSource->getURL(), css::uno::Sequence<css::beans::NamedValue>(&prop, 1),
504 0 : "shared", xAbortChannel, m_updateCmdEnv.get());
505 0 : }
506 : }
507 0 : catch (css::deployment::DeploymentException & de)
508 : {
509 0 : if (de.Cause.has<css::deployment::LicenseException>())
510 : {
511 0 : bLicenseDeclined = true;
512 : }
513 : else
514 : {
515 0 : exc = de.Cause.get<cssu::Exception>();
516 0 : bError = true;
517 : }
518 : }
519 0 : catch (cssu::Exception& e)
520 : {
521 0 : exc = e;
522 0 : bError = true;
523 : }
524 :
525 0 : if (bLicenseDeclined)
526 : {
527 0 : SolarMutexGuard g;
528 0 : if (m_stop) {
529 0 : return;
530 : }
531 : m_dialog.setError(UpdateInstallDialog::ERROR_LICENSE_DECLINED,
532 0 : curData.aInstalledPackage->getDisplayName(), OUString());
533 : }
534 0 : else if (!xExtension.is() || bError)
535 : {
536 0 : SolarMutexGuard g;
537 0 : if (m_stop) {
538 0 : return;
539 : }
540 : m_dialog.setError(UpdateInstallDialog::ERROR_INSTALLATION,
541 0 : curData.aInstalledPackage->getDisplayName(), exc.Message);
542 : }
543 0 : }
544 : {
545 0 : SolarMutexGuard g;
546 0 : if (m_stop) {
547 0 : return;
548 : }
549 0 : m_dialog.m_statusbar.SetValue(100);
550 0 : m_dialog.m_ft_extension_name.SetText(OUString());
551 0 : m_dialog.m_ft_action.SetText(m_dialog.m_sFinished);
552 : }
553 : }
554 :
555 0 : void UpdateInstallDialog::Thread::removeTempDownloads()
556 : {
557 0 : if (!m_sDownloadFolder.isEmpty())
558 : {
559 : dp_misc::erase_path(m_sDownloadFolder,
560 0 : cssu::Reference<css::ucb::XCommandEnvironment>(),false /* no throw: ignore errors */ );
561 : //remove also the temp file which we have used to create the unique name
562 0 : OUString tempFile = m_sDownloadFolder.copy(0, m_sDownloadFolder.getLength() - 1);
563 0 : dp_misc::erase_path(tempFile, cssu::Reference<css::ucb::XCommandEnvironment>(),false);
564 0 : m_sDownloadFolder = OUString();
565 : }
566 0 : }
567 :
568 0 : void UpdateInstallDialog::Thread::download(OUString const & sDownloadURL, UpdateData & aUpdateData)
569 : {
570 : {
571 0 : SolarMutexGuard g;
572 0 : if (m_stop) {
573 0 : return;
574 0 : }
575 : }
576 :
577 : OSL_ASSERT(m_sDownloadFolder.getLength());
578 0 : OUString destFolder, tempEntry;
579 0 : if (::osl::File::createTempFile(
580 : &m_sDownloadFolder,
581 0 : 0, &tempEntry ) != ::osl::File::E_None)
582 : {
583 : //ToDo feedback in window that download of this component failed
584 0 : throw cssu::Exception("Could not create temporary file in folder " + destFolder + ".", 0);
585 : }
586 0 : tempEntry = tempEntry.copy( tempEntry.lastIndexOf( '/' ) + 1 );
587 :
588 0 : destFolder = dp_misc::makeURL( m_sDownloadFolder, tempEntry );
589 0 : destFolder += "_";
590 :
591 0 : ::ucbhelper::Content destFolderContent;
592 0 : dp_misc::create_folder( &destFolderContent, destFolder, m_updateCmdEnv.get() );
593 :
594 0 : ::ucbhelper::Content sourceContent;
595 0 : dp_misc::create_ucb_content( &sourceContent, sDownloadURL, m_updateCmdEnv.get() );
596 :
597 0 : const OUString sTitle( StrTitle::getTitle( sourceContent ) );
598 :
599 0 : if (destFolderContent.transferContent(
600 : sourceContent, ::ucbhelper::InsertOperation_COPY,
601 0 : sTitle, css::ucb::NameClash::OVERWRITE ))
602 : {
603 : //the user may have cancelled the dialog because downloading took to long
604 : {
605 0 : SolarMutexGuard g;
606 0 : if (m_stop) {
607 0 : return;
608 : }
609 : //all errors should be handeld by the command environment.
610 0 : aUpdateData.sLocalURL = destFolder + "/" + sTitle;
611 : }
612 0 : }
613 : }
614 :
615 0 : UpdateCommandEnv::UpdateCommandEnv( cssu::Reference< cssu::XComponentContext > const & xCtx,
616 : ::rtl::Reference<UpdateInstallDialog::Thread>const & thread)
617 : : m_installThread(thread),
618 0 : m_xContext(xCtx)
619 : {
620 0 : }
621 :
622 0 : UpdateCommandEnv::~UpdateCommandEnv()
623 : {
624 0 : }
625 :
626 : // XCommandEnvironment
627 0 : cssu::Reference<css::task::XInteractionHandler> UpdateCommandEnv::getInteractionHandler()
628 : throw (cssu::RuntimeException, std::exception)
629 : {
630 0 : return this;
631 : }
632 :
633 0 : cssu::Reference<css::ucb::XProgressHandler> UpdateCommandEnv::getProgressHandler()
634 : throw (cssu::RuntimeException, std::exception)
635 : {
636 0 : return this;
637 : }
638 :
639 : // XInteractionHandler
640 0 : void UpdateCommandEnv::handle(
641 : cssu::Reference< css::task::XInteractionRequest> const & xRequest )
642 : throw (cssu::RuntimeException, std::exception)
643 : {
644 0 : cssu::Any request( xRequest->getRequest() );
645 : OSL_ASSERT( request.getValueTypeClass() == cssu::TypeClass_EXCEPTION );
646 : dp_misc::TRACE("[dp_gui_cmdenv.cxx] incoming request:\n"
647 0 : + ::comphelper::anyToString(request) + "\n\n");
648 :
649 0 : css::deployment::VersionException verExc;
650 0 : bool approve = false;
651 :
652 0 : if (request >>= verExc)
653 : { //We must catch the version exception during the update,
654 : //because otherwise the user would be confronted with the dialogs, asking
655 : //them if they want to replace an already installed version of the same extension.
656 : //During an update we assume that we always want to replace the old version with the
657 : //new version.
658 0 : approve = true;
659 : }
660 :
661 0 : if (approve == false)
662 : {
663 : //forward to interaction handler for main dialog.
664 0 : handleInteractionRequest( m_xContext, xRequest );
665 : }
666 : else
667 : {
668 : // select:
669 : cssu::Sequence< cssu::Reference< css::task::XInteractionContinuation > > conts(
670 0 : xRequest->getContinuations() );
671 : cssu::Reference< css::task::XInteractionContinuation > const * pConts =
672 0 : conts.getConstArray();
673 0 : sal_Int32 len = conts.getLength();
674 0 : for ( sal_Int32 pos = 0; pos < len; ++pos )
675 : {
676 0 : if (approve) {
677 : cssu::Reference< css::task::XInteractionApprove > xInteractionApprove(
678 0 : pConts[ pos ], cssu::UNO_QUERY );
679 0 : if (xInteractionApprove.is()) {
680 0 : xInteractionApprove->select();
681 : // don't query again for ongoing continuations:
682 0 : approve = false;
683 0 : }
684 : }
685 0 : }
686 0 : }
687 0 : }
688 :
689 : // XProgressHandler
690 0 : void UpdateCommandEnv::push( cssu::Any const & /*Status*/ )
691 : throw (cssu::RuntimeException, std::exception)
692 : {
693 0 : }
694 :
695 0 : void UpdateCommandEnv::update( cssu::Any const & /*Status */)
696 : throw (cssu::RuntimeException, std::exception)
697 : {
698 0 : }
699 :
700 0 : void UpdateCommandEnv::pop() throw (cssu::RuntimeException, std::exception)
701 : {
702 0 : }
703 :
704 :
705 : } //end namespace dp_gui
706 :
707 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|