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