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