android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / ui / dbui / mmoutputtypepage.cxx
blobc139bb0943c12e2e332e68f2c0580f5dd8e36f4e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include "mmoutputtypepage.hxx"
21 #include <mailmergewizard.hxx>
22 #include <mmconfigitem.hxx>
23 #include <strings.hrc>
24 #include <bitmaps.hlst>
25 #include <swtypes.hxx>
27 #include <osl/diagnose.h>
28 #include <rtl/ref.hxx>
29 #include <com/sun/star/mail/XSmtpService.hpp>
30 #include <vcl/idle.hxx>
31 #include <vcl/svapp.hxx>
32 #include <vcl/weld.hxx>
34 #include <swunohelper.hxx>
35 #include <mmresultdialogs.hxx>
36 #include <maildispatcher.hxx>
37 #include <imaildsplistener.hxx>
38 #include <mutex>
40 using namespace ::com::sun::star;
42 SwMailMergeOutputTypePage::SwMailMergeOutputTypePage(weld::Container* pPage, SwMailMergeWizard* pWizard)
43 : vcl::OWizardPage(pPage, pWizard, "modules/swriter/ui/mmoutputtypepage.ui", "MMOutputTypePage")
44 , m_pWizard(pWizard)
45 , m_xLetterRB(m_xBuilder->weld_radio_button("letter"))
46 , m_xMailRB(m_xBuilder->weld_radio_button("email"))
47 , m_xLetterHint(m_xBuilder->weld_label("letterft"))
48 , m_xMailHint(m_xBuilder->weld_label("emailft"))
50 Link<weld::Toggleable&,void> aLink = LINK(this, SwMailMergeOutputTypePage, TypeHdl_Impl);
51 m_xLetterRB->connect_toggled(aLink);
52 m_xMailRB->connect_toggled(aLink);
54 SwMailMergeConfigItem& rConfigItem = m_pWizard->GetConfigItem();
55 if(rConfigItem.IsOutputToLetter())
56 m_xLetterRB->set_active(true);
57 else
58 m_xMailRB->set_active(true);
59 TypeHdl_Impl(*m_xLetterRB);
62 SwMailMergeOutputTypePage::~SwMailMergeOutputTypePage()
66 IMPL_LINK_NOARG(SwMailMergeOutputTypePage, TypeHdl_Impl, weld::Toggleable&, void)
68 bool bLetter = m_xLetterRB->get_active();
69 m_xLetterHint->set_visible(bLetter);
70 m_xMailHint->set_visible(!bLetter);
71 m_pWizard->GetConfigItem().SetOutputToLetter(bLetter);
72 m_pWizard->UpdateRoadmap();
75 struct SwSendMailDialog_Impl
77 friend class SwSendMailDialog;
78 // The mutex is locked in SwSendMailDialog_Impl::GetNextDescriptor, which may be called
79 // both with mutex unlocked (inside SwSendMailDialog::SendMails), and with mutex locked
80 // (inside SwSendMailDialog::AddDocument).
81 std::recursive_mutex aDescriptorMutex;
83 std::vector< SwMailDescriptor > aDescriptors;
84 sal_uInt32 nCurrentDescriptor;
85 ::rtl::Reference< MailDispatcher > xMailDispatcher;
86 ::rtl::Reference< IMailDispatcherListener> xMailListener;
87 uno::Reference< mail::XMailService > xConnectedInMailService;
88 Idle aRemoveIdle;
90 SwSendMailDialog_Impl() :
91 nCurrentDescriptor(0), aRemoveIdle("SwSendMailDialog_Impl aRemoveIdle")
93 aRemoveIdle.SetPriority(TaskPriority::LOWEST);
96 ~SwSendMailDialog_Impl()
98 // Shutdown must be called when the last reference to the
99 // mail dispatcher will be released in order to force a
100 // shutdown of the mail dispatcher thread.
101 // 'join' with the mail dispatcher thread leads to a
102 // deadlock (SolarMutex).
103 if( xMailDispatcher.is() && !xMailDispatcher->isShutdownRequested() )
104 xMailDispatcher->shutdown();
106 const SwMailDescriptor* GetNextDescriptor();
109 const SwMailDescriptor* SwSendMailDialog_Impl::GetNextDescriptor()
111 std::scoped_lock aGuard(aDescriptorMutex);
112 if(nCurrentDescriptor < aDescriptors.size())
114 ++nCurrentDescriptor;
115 return &aDescriptors[nCurrentDescriptor - 1];
117 return nullptr;
120 namespace {
122 class SwMailDispatcherListener_Impl : public IMailDispatcherListener
124 SwSendMailDialog& m_rSendMailDialog;
126 public:
127 explicit SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg);
129 virtual void idle() override;
130 virtual void mailDelivered(uno::Reference< mail::XMailMessage> xMailMessage) override;
131 virtual void mailDeliveryError(::rtl::Reference<MailDispatcher> xMailDispatcher,
132 uno::Reference< mail::XMailMessage> xMailMessage, const OUString& sErrorMessage) override;
134 static void DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage );
139 SwMailDispatcherListener_Impl::SwMailDispatcherListener_Impl(SwSendMailDialog& rParentDlg)
140 : m_rSendMailDialog(rParentDlg)
144 void SwMailDispatcherListener_Impl::idle()
146 SolarMutexGuard aGuard;
147 m_rSendMailDialog.AllMailsSent();
150 void SwMailDispatcherListener_Impl::mailDelivered(
151 uno::Reference< mail::XMailMessage> xMailMessage)
153 SolarMutexGuard aGuard;
154 m_rSendMailDialog.DocumentSent( xMailMessage, true, nullptr );
155 DeleteAttachments( xMailMessage );
158 void SwMailDispatcherListener_Impl::mailDeliveryError(
159 ::rtl::Reference<MailDispatcher> /*xMailDispatcher*/,
160 uno::Reference< mail::XMailMessage> xMailMessage,
161 const OUString& sErrorMessage)
163 SolarMutexGuard aGuard;
164 m_rSendMailDialog.DocumentSent( xMailMessage, false, &sErrorMessage );
165 DeleteAttachments( xMailMessage );
168 void SwMailDispatcherListener_Impl::DeleteAttachments( uno::Reference< mail::XMailMessage > const & xMessage )
170 const uno::Sequence< mail::MailAttachment > aAttachments = xMessage->getAttachments();
172 for(const auto& rAttachment : aAttachments)
176 uno::Reference< beans::XPropertySet > xTransferableProperties( rAttachment.Data, uno::UNO_QUERY_THROW);
177 OUString sURL;
178 xTransferableProperties->getPropertyValue("URL") >>= sURL;
179 if(!sURL.isEmpty())
180 SWUnoHelper::UCB_DeleteFile( sURL );
182 catch (const uno::Exception&)
188 namespace {
190 class SwSendWarningBox_Impl : public weld::MessageDialogController
192 std::unique_ptr<weld::TextView> m_xDetailED;
193 public:
194 SwSendWarningBox_Impl(weld::Window* pParent, const OUString& rDetails)
195 : MessageDialogController(pParent, "modules/swriter/ui/warnemaildialog.ui", "WarnEmailDialog", "grid")
196 , m_xDetailED(m_xBuilder->weld_text_view("errors"))
198 m_xDetailED->set_size_request(80 * m_xDetailED->get_approximate_digit_width(),
199 8 * m_xDetailED->get_text_height());
200 m_xDetailED->set_text(rDetails);
206 SwSendMailDialog::SwSendMailDialog(weld::Window *pParent, SwMailMergeConfigItem& rConfigItem)
207 : GenericDialogController(pParent, "modules/swriter/ui/mmsendmails.ui", "SendMailsDialog")
208 , m_sContinue(SwResId( ST_CONTINUE ))
209 , m_sClose(SwResId(ST_CLOSE_DIALOG))
210 , m_sSendingTo( SwResId(ST_SENDINGTO ))
211 , m_sCompleted( SwResId(ST_COMPLETED ))
212 , m_sFailed( SwResId(ST_FAILED ))
213 , m_sAddressInvalid(SwResId(ST_ADDRESS_INVALID))
214 , m_bCancel(false)
215 , m_bDestructionEnabled(false)
216 , m_pImpl(new SwSendMailDialog_Impl)
217 , m_pConfigItem(&rConfigItem)
218 , m_nExpectedCount(0)
219 , m_nProcessedCount(0)
220 , m_nErrorCount(0)
221 , m_xTransferStatus(m_xBuilder->weld_label("transferstatus"))
222 , m_xPaused(m_xBuilder->weld_label("paused"))
223 , m_xProgressBar(m_xBuilder->weld_progress_bar("progress"))
224 , m_xErrorStatus(m_xBuilder->weld_label("errorstatus"))
225 , m_xStatus(m_xBuilder->weld_tree_view("container"))
226 , m_xStop(m_xBuilder->weld_button("stop"))
227 , m_xCancel(m_xBuilder->weld_button("cancel"))
229 m_sStop = m_xStop->get_label();
230 m_sTransferStatus = m_xTransferStatus->get_label();
231 m_sErrorStatus = m_xErrorStatus->get_label();
233 Size aSize(m_xStatus->get_approximate_digit_width() * 28,
234 m_xStatus->get_height_rows(20));
235 m_xStatus->set_size_request(aSize.Width(), aSize.Height());
237 m_xStop->connect_clicked(LINK( this, SwSendMailDialog, StopHdl_Impl));
238 m_xCancel->connect_clicked(LINK( this, SwSendMailDialog, CancelHdl_Impl));
240 std::vector<int> aWidths
242 o3tl::narrowing<int>(m_xStatus->get_checkbox_column_width()),
243 o3tl::narrowing<int>(aSize.Width()/3 * 2)
245 m_xStatus->set_column_fixed_widths(aWidths);
247 m_xPaused->set_visible(false);
248 UpdateTransferStatus();
251 SwSendMailDialog::~SwSendMailDialog()
253 if(!m_pImpl->xMailDispatcher.is())
254 return;
258 if(m_pImpl->xMailDispatcher->isStarted())
259 m_pImpl->xMailDispatcher->stop();
260 if(m_pImpl->xConnectedInMailService.is() && m_pImpl->xConnectedInMailService->isConnected())
261 m_pImpl->xConnectedInMailService->disconnect();
263 uno::Reference<mail::XMailMessage> xMessage =
264 m_pImpl->xMailDispatcher->dequeueMailMessage();
265 while(xMessage.is())
267 SwMailDispatcherListener_Impl::DeleteAttachments( xMessage );
268 xMessage = m_pImpl->xMailDispatcher->dequeueMailMessage();
271 catch (const uno::Exception&)
276 void SwSendMailDialog::AddDocument( SwMailDescriptor const & rDesc )
278 std::scoped_lock aGuard(m_pImpl->aDescriptorMutex);
279 m_pImpl->aDescriptors.push_back(rDesc);
280 // if the dialog is already running then continue sending of documents
281 if(m_pImpl->xMailDispatcher.is())
283 IterateMails();
287 IMPL_LINK( SwSendMailDialog, StopHdl_Impl, weld::Button&, rButton, void )
289 m_bCancel = true;
290 if(!m_pImpl->xMailDispatcher.is())
291 return;
293 if(m_pImpl->xMailDispatcher->isStarted())
295 m_pImpl->xMailDispatcher->stop();
296 rButton.set_label(m_sContinue);
297 m_xPaused->show();
299 else
301 m_pImpl->xMailDispatcher->start();
302 rButton.set_label(m_sStop);
303 m_xPaused->hide();
307 IMPL_LINK_NOARG(SwSendMailDialog, CancelHdl_Impl, weld::Button&, void)
309 m_xDialog->hide();
311 if (m_bDestructionEnabled)
312 m_xDialog->response(RET_CANCEL);
313 else
315 m_pImpl->aRemoveIdle.SetInvokeHandler( LINK( this, SwSendMailDialog, RemoveThis ) );
316 m_pImpl->aRemoveIdle.Start();
320 IMPL_STATIC_LINK( SwSendMailDialog, StartSendMails, void*, pDialog, void )
322 static_cast<SwSendMailDialog*>(pDialog)->SendMails();
325 IMPL_LINK( SwSendMailDialog, RemoveThis, Timer*, pTimer, void )
327 if( m_pImpl->xMailDispatcher.is() )
329 if(m_pImpl->xMailDispatcher->isStarted())
330 m_pImpl->xMailDispatcher->stop();
331 if(!m_pImpl->xMailDispatcher->isShutdownRequested())
332 m_pImpl->xMailDispatcher->shutdown();
335 if( m_bDestructionEnabled &&
336 (!m_pImpl->xMailDispatcher.is() ||
337 !m_pImpl->xMailDispatcher->isRunning()))
339 m_xDialog->response(RET_CANCEL);
341 else
343 pTimer->Start();
347 IMPL_STATIC_LINK( SwSendMailDialog, StopSendMails, void*, p, void )
349 SwSendMailDialog* pDialog = static_cast<SwSendMailDialog*>(p);
350 if(pDialog->m_pImpl->xMailDispatcher.is() &&
351 pDialog->m_pImpl->xMailDispatcher->isStarted())
353 pDialog->m_pImpl->xMailDispatcher->stop();
354 pDialog->m_xStop->set_label(pDialog->m_sContinue);
355 pDialog->m_xPaused->show();
359 void SwSendMailDialog::SendMails()
361 if(!m_pConfigItem)
363 OSL_FAIL("config item not set");
364 return;
366 auto xWait(std::make_unique<weld::WaitObject>(m_xDialog.get()));
367 //get a mail server connection
368 uno::Reference< mail::XSmtpService > xSmtpServer =
369 SwMailMergeHelper::ConnectToSmtpServer( *m_pConfigItem,
370 m_pImpl->xConnectedInMailService,
371 OUString(), OUString(), m_xDialog.get());
372 bool bIsLoggedIn = xSmtpServer.is() && xSmtpServer->isConnected();
373 xWait.reset();
374 if(!bIsLoggedIn)
376 OSL_FAIL("create error message");
377 return;
379 m_pImpl->xMailDispatcher.set( new MailDispatcher(xSmtpServer));
380 IterateMails();
381 m_pImpl->xMailListener = new SwMailDispatcherListener_Impl(*this);
382 m_pImpl->xMailDispatcher->addListener(m_pImpl->xMailListener);
383 if(!m_bCancel)
385 m_pImpl->xMailDispatcher->start();
389 void SwSendMailDialog::IterateMails()
391 const SwMailDescriptor* pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
392 while( pCurrentMailDescriptor )
394 if (!SwMailMergeHelper::CheckMailAddress( pCurrentMailDescriptor->sEMail))
396 OUString sMessage = m_sSendingTo;
397 m_xStatus->append();
398 m_xStatus->set_image(m_nProcessedCount, RID_BMP_FORMULA_CANCEL, 0);
399 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", pCurrentMailDescriptor->sEMail), 1);
400 m_xStatus->set_text(m_nProcessedCount, m_sAddressInvalid, 2);
401 ++m_nProcessedCount;
402 ++m_nErrorCount;
403 UpdateTransferStatus( );
404 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
405 continue;
407 rtl::Reference<SwMailMessage> pMessage = new SwMailMessage;
408 if(m_pConfigItem->IsMailReplyTo())
409 pMessage->setReplyToAddress(m_pConfigItem->GetMailReplyTo());
410 pMessage->addRecipient( pCurrentMailDescriptor->sEMail );
411 pMessage->SetSenderName( m_pConfigItem->GetMailDisplayName() );
412 pMessage->SetSenderAddress( m_pConfigItem->GetMailAddress() );
413 if(!pCurrentMailDescriptor->sAttachmentURL.isEmpty())
415 mail::MailAttachment aAttach;
416 aAttach.Data =
417 new SwMailTransferable(
418 pCurrentMailDescriptor->sAttachmentURL,
419 pCurrentMailDescriptor->sAttachmentName,
420 pCurrentMailDescriptor->sMimeType );
421 aAttach.ReadableName = pCurrentMailDescriptor->sAttachmentName;
422 pMessage->addAttachment( aAttach );
424 pMessage->setSubject( pCurrentMailDescriptor->sSubject );
425 uno::Reference< datatransfer::XTransferable> xBody =
426 new SwMailTransferable(
427 pCurrentMailDescriptor->sBodyContent,
428 pCurrentMailDescriptor->sBodyMimeType);
429 pMessage->setBody( xBody );
431 //CC and BCC are tokenized by ';'
432 if(!pCurrentMailDescriptor->sCC.isEmpty())
434 sal_Int32 nPos = 0;
437 OUString sTmp = pCurrentMailDescriptor->sCC.getToken( 0, ';', nPos );
438 if( !sTmp.isEmpty() )
439 pMessage->addCcRecipient( sTmp );
441 while (nPos >= 0);
443 if(!pCurrentMailDescriptor->sBCC.isEmpty())
445 sal_Int32 nPos = 0;
448 OUString sTmp = pCurrentMailDescriptor->sBCC.getToken( 0, ';', nPos );
449 if( !sTmp.isEmpty() )
450 pMessage->addBccRecipient( sTmp );
452 while (nPos >= 0);
454 m_pImpl->xMailDispatcher->enqueueMailMessage( pMessage );
455 pCurrentMailDescriptor = m_pImpl->GetNextDescriptor();
457 UpdateTransferStatus();
460 void SwSendMailDialog::StartSend(sal_Int32 nExpectedCount)
462 Application::PostUserEvent( LINK( this, SwSendMailDialog,
463 StartSendMails ), this );
464 m_nExpectedCount = nExpectedCount > 0 ? nExpectedCount : 1;
467 void SwSendMailDialog::DocumentSent( uno::Reference< mail::XMailMessage> const & xMessage,
468 bool bResult,
469 const OUString* pError )
471 //sending should stop on send errors, except after last error - it will stop in AllMailsSent
472 if (pError && m_nProcessedCount + 1 < m_nExpectedCount &&
473 m_pImpl->xMailDispatcher.is() && m_pImpl->xMailDispatcher->isStarted())
475 Application::PostUserEvent( LINK( this, SwSendMailDialog,
476 StopSendMails ), this );
478 OUString sInsertImg(bResult ? OUString(RID_BMP_FORMULA_APPLY) : OUString(RID_BMP_FORMULA_CANCEL));
480 OUString sMessage = m_sSendingTo;
481 m_xStatus->append();
482 m_xStatus->set_image(m_nProcessedCount, sInsertImg, 0);
483 m_xStatus->set_text(m_nProcessedCount, sMessage.replaceFirst("%1", xMessage->getRecipients()[0]), 1);
484 m_xStatus->set_text(m_nProcessedCount, bResult ? m_sCompleted : m_sFailed, 2);
485 ++m_nProcessedCount;
486 if(!bResult)
487 ++m_nErrorCount;
489 UpdateTransferStatus( );
491 if (pError)
493 SwSendWarningBox_Impl aDlg(m_xDialog.get(), *pError);
494 aDlg.run();
498 void SwSendMailDialog::UpdateTransferStatus()
500 OUString sStatus( m_sTransferStatus );
501 sStatus = sStatus.replaceFirst("%1", OUString::number(m_nProcessedCount) );
502 sStatus = sStatus.replaceFirst("%2", OUString::number(m_nExpectedCount));
503 m_xTransferStatus->set_label(sStatus);
505 sStatus = m_sErrorStatus.replaceFirst("%1", OUString::number(m_nErrorCount) );
506 m_xErrorStatus->set_label(sStatus);
508 if (!m_pImpl->aDescriptors.empty())
510 assert(m_nExpectedCount && "div-by-zero");
511 m_xProgressBar->set_percentage(m_nProcessedCount * 100 / m_nExpectedCount);
513 else
514 m_xProgressBar->set_percentage(0);
517 void SwSendMailDialog::AllMailsSent()
519 if (m_nProcessedCount == m_nExpectedCount)
521 m_xStop->set_sensitive(false);
522 m_xCancel->set_label(m_sClose);
523 // Leave open if some kind of error occurred
524 if (m_nErrorCount == 0)
526 m_xDialog->hide();
527 m_xDialog->response(RET_CANCEL);
532 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */