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 #ifndef INCLUDED_SW_INC_DBMGR_HXX
20 #define INCLUDED_SW_INC_DBMGR_HXX
21 
22 #include <rtl/ustring.hxx>
23 #include <tools/solar.h>
24 #include <tools/long.hxx>
25 #include <i18nlangtag/lang.h>
26 #include <com/sun/star/util/Date.hpp>
27 #include "swdllapi.h"
28 #include "swdbdata.hxx"
29 #include <com/sun/star/uno/Reference.h>
30 #include <com/sun/star/uno/Sequence.hxx>
31 #include <com/sun/star/lang/Locale.hpp>
32 #include <com/sun/star/beans/PropertyValue.hpp>
33 
34 #include <memory>
35 #include <vector>
36 
37 namespace com::sun::star{
38     namespace sdbc{
39         class XConnection;
40         class XStatement;
41         class XDataSource;
42         class XResultSet;
43     }
44     namespace beans{
45 
46         class XPropertySet;
47     }
48     namespace sdbcx{
49         class XColumnsSupplier;
50     }
51     namespace util{
52         class XNumberFormatter;
53     }
54     namespace mail{
55         class XSmtpService;
56     }
57     namespace embed { class XStorage; }
58     namespace frame { class XStorable; }
59 }
60 namespace svx {
61     class ODataAccessDescriptor;
62 }
63 
64 struct SwDBFormatData
65 {
66     css::util::Date aNullDate;
67     css::uno::Reference< css::util::XNumberFormatter> xFormatter;
68     css::lang::Locale aLocale;
69 };
70 
71 namespace weld {
72     class ComboBox;
73     class Window;
74 }
75 
76 class SwView;
77 class SwWrtShell;
78 class ListBox;
79 class SvNumberFormatter;
80 class SwXMailMerge;
81 class SwMailMergeConfigItem;
82 class SwCalc;
83 class INetURLObject;
84 class SwDocShell;
85 
86 enum DBManagerOptions
87 {
88     DBMGR_MERGE,             ///< Data records in fields.
89     DBMGR_MERGE_PRINTER,     ///< Print mail merge.
90     DBMGR_MERGE_EMAIL,       ///< Send mail merge as email.
91     DBMGR_MERGE_FILE,        ///< Save mail merge as files.
92     DBMGR_MERGE_SHELL        ///< Create merge doc and keep the doc shell.
93 };
94 
95 // Administration of (new) logical databases.
96 enum class SwDBSelect
97 {
98     UNKNOWN, TABLE, QUERY
99 };
100 
101 struct SwDSParam : public SwDBData
102 {
103     css::util::Date  aNullDate;
104 
105     css::uno::Reference<css::util::XNumberFormatter>    xFormatter;
106     css::uno::Reference< css::sdbc::XConnection>       xConnection;
107     css::uno::Reference< css::sdbc::XStatement>        xStatement;
108     css::uno::Reference< css::sdbc::XResultSet>        xResultSet;
109     css::uno::Sequence<  css::uno::Any >               aSelection;
110     bool bScrollable;
111     bool bEndOfDB;
112     tools::Long nSelectionIndex;
113 
SwDSParamSwDSParam114     SwDSParam(const SwDBData& rData) :
115         SwDBData(rData),
116         bScrollable(false),
117         bEndOfDB(false),
118         nSelectionIndex(0)
119         {}
120 
SwDSParamSwDSParam121     SwDSParam(const SwDBData& rData,
122         const css::uno::Reference< css::sdbc::XResultSet>&    xResSet,
123         const css::uno::Sequence<  css::uno::Any >&   rSelection) :
124         SwDBData(rData),
125         xResultSet(xResSet),
126         aSelection(rSelection),
127         bScrollable(true),
128         bEndOfDB(false),
129         nSelectionIndex(0)
130         {}
131 
HasValidRecordSwDSParam132     bool HasValidRecord() const
133         { return( !bEndOfDB && xResultSet.is() ); }
134 };
135 
136 typedef std::vector<std::unique_ptr<SwDSParam>> SwDSParams_t;
137 
138 struct SwMergeDescriptor
139 {
140     const DBManagerOptions                              nMergeType;
141     SwWrtShell&                                         rSh;
142     const svx::ODataAccessDescriptor&                   rDescriptor;
143 
144     /**
145      * Create a single or multiple results
146      *
147      * This currently just affects FILE, as EMAIL is always
148      * multiple and SHELL and PRINTER are always single.
149      */
150     bool                                                bCreateSingleFile;
151 
152     /**
153      * @defgroup save Export filter settings
154      * @addtogroup save
155      * @{ */
156     OUString                                            sSaveToFilter;
157     OUString                                            sSaveToFilterOptions;
158     css::uno::Sequence< css::beans::PropertyValue >     aSaveToFilterData;
159     /** @} */
160 
161     /**
162      * @defgroup file Mail merge as File settings
163      * @addtogroup file
164      * @{ */
165 
166     /**
167      * Basename incl. the path for the generated files.
168      *
169      * The final filename will be created by concatenating a number to prevent
170      * overwriting an existing file and the extension based on the filter
171      * settings.
172      */
173     OUString                                            sPrefix;
174     /**
175      * Use the sPrefix as the target filename also overwriting an existing
176      * target file.
177      *
178      * Just used for the internal mail merge dialogs as mail merge never
179      * overwrites existing files (see SwDBManager::ExecuteFormLetter).
180      */
181     bool                                                bPrefixIsFilename;
182     /** @} */
183 
184     /**
185      * @defgroup email Mail merge as eMail settings
186      * @addtogroup email
187      * @{ */
188     OUString                                            sSubject;
189     OUString                                            sMailBody;
190     OUString                                            sAttachmentName;
191     css::uno::Sequence< OUString >                      aCopiesTo;
192     css::uno::Sequence< OUString >                      aBlindCopiesTo;
193     css::uno::Reference< css::mail::XSmtpService >      xSmtpServer;
194     bool                                                bSendAsHTML;
195     bool                                                bSendAsAttachment;
196     /** @} */
197 
198     /**
199      * @addtogroup file email
200      * @{ */
201 
202     /** DB column to fetch EMail of Filename from
203      */
204     OUString                                            sDBcolumn;
205 
206     /** DB column to fetch password
207      */
208     OUString                                            sDBPasswordColumn;
209 
210     /** @} */
211 
212     /**
213      * @defgroup print Mail merge to Printer
214      * @addtogroup print
215      * @{ */
216     css::uno::Sequence<  css::beans::PropertyValue >    aPrintOptions;
217     /** @} */
218 
219     SwMailMergeConfigItem*                              pMailMergeConfigItem;
220 
SwMergeDescriptorSwMergeDescriptor221     SwMergeDescriptor( const DBManagerOptions nType,
222                        SwWrtShell& rShell,
223                        const svx::ODataAccessDescriptor& rDesc ) :
224         nMergeType(nType),
225         rSh(rShell),
226         rDescriptor(rDesc),
227         bCreateSingleFile( false ),
228         bPrefixIsFilename( false ),
229         bSendAsHTML( true ),
230         bSendAsAttachment( false ),
231         pMailMergeConfigItem( nullptr )
232     {
233         if( nType == DBMGR_MERGE_SHELL || nType == DBMGR_MERGE_PRINTER )
234             bCreateSingleFile = true;
235     }
236 };
237 
238 class SwDoc;
239 
240 class SW_DLLPUBLIC SwDBManager
241 {
242     struct SwDBManager_Impl;
243     class SAL_DLLPRIVATE ConnectionDisposedListener_Impl;
244     class MailDispatcherListener_Impl;
245 
246     enum class MergeStatus
247     {
248         Ok = 0, Cancel, Error
249     };
250 
251     MergeStatus     m_aMergeStatus;     ///< current / last merge status
252     bool            m_bInitDBFields : 1;
253     bool            m_bInMerge    : 1;    ///< merge process active
254     bool            m_bMergeSilent : 1;   ///< suppress display of dialogs/boxes (used when called over API)
255     SwDSParams_t    m_DataSourceParams;
256     std::unique_ptr<SwDBManager_Impl>  m_pImpl;
257     const SwXMailMerge* m_pMergeEvtSrc;   ///< != 0 if mail merge events are to be send
258     /// Name of the embedded database that's included in the current document.
259     OUString     m_sEmbeddedName;
260 
261     /// Store last registrations to revoke or commit
262     static std::vector<std::pair<SwDocShell*, OUString>> m_aUncommittedRegistrations;
263 
264     /// Not used connections.
265     std::vector<OUString> m_aNotUsedConnections;
266 
267     /// Set connection as used.
268     void SetAsUsed(const OUString& rName);
269 
270     /// The document that owns this manager.
271     SwDoc* m_pDoc;
272 
273     SAL_DLLPRIVATE SwDSParam*          FindDSData(const SwDBData& rData, bool bCreate);
274     SAL_DLLPRIVATE SwDSParam*          FindDSConnection(const OUString& rSource, bool bCreate);
275 
276     /// Insert data record as text into document.
277     SAL_DLLPRIVATE void ImportFromConnection( SwWrtShell* pSh);
278 
279     /// Insert a single data record as text into document.
280     SAL_DLLPRIVATE void ImportDBEntry(SwWrtShell* pSh);
281 
282     /// Run the mail merge for defined modes, except DBMGR_MERGE
283     SAL_DLLPRIVATE bool MergeMailFiles( SwWrtShell* pSh,
284                                         const SwMergeDescriptor& rMergeDescriptor );
285 
286     SAL_DLLPRIVATE bool ToNextMergeRecord();
287     SAL_DLLPRIVATE bool IsValidMergeRecord() const;
288 
289     SwDBManager(SwDBManager const&) = delete;
290     SwDBManager& operator=(SwDBManager const&) = delete;
291 
292 public:
293     SwDBManager(SwDoc* pDoc);
294     ~SwDBManager() COVERITY_NOEXCEPT_FALSE;
295 
296     /// MailMergeEvent source
GetMailMergeEvtSrc() const297     const SwXMailMerge *    GetMailMergeEvtSrc() const  { return m_pMergeEvtSrc; }
SetMailMergeEvtSrc(const SwXMailMerge * pSrc)298     void SetMailMergeEvtSrc( const SwXMailMerge *pSrc ) { m_pMergeEvtSrc = pSrc; }
299 
IsMergeSilent() const300     bool     IsMergeSilent() const           { return m_bMergeSilent; }
SetMergeSilent(bool bVal)301     void     SetMergeSilent( bool bVal )     { m_bMergeSilent = bVal; }
302 
303     /// Merging of data records into fields.
304     bool            Merge( const SwMergeDescriptor& rMergeDesc );
305     void            MergeCancel();
306 
IsMergeOk() const307     bool     IsMergeOk() const     { return MergeStatus::Ok     == m_aMergeStatus; }
IsMergeError() const308     bool     IsMergeError() const  { return MergeStatus::Error  <= m_aMergeStatus; }
309 
310     static std::shared_ptr<SwMailMergeConfigItem> PerformMailMerge(SwView const * pView);
311 
312     /// Initialize data fields that lack name of database.
IsInitDBFields() const313     bool     IsInitDBFields() const  { return m_bInitDBFields; }
SetInitDBFields(bool b)314     void     SetInitDBFields(bool b) { m_bInitDBFields = b;    }
315 
316     /// Fill listbox with all table names of a database.
317     bool            GetTableNames(weld::ComboBox& rBox, const OUString& rDBName);
318 
319     /// Fill listbox with all column names of a database table.
320     void            GetColumnNames(weld::ComboBox& rBox,
321                             const OUString& rDBName, const OUString& rTableName);
322     static void GetColumnNames(weld::ComboBox& rBox,
323                             css::uno::Reference< css::sdbc::XConnection> const & xConnection,
324                             const OUString& rTableName);
325 
326     static sal_uLong GetColumnFormat( css::uno::Reference< css::sdbc::XDataSource> const & xSource,
327                             css::uno::Reference< css::sdbc::XConnection> const & xConnection,
328                             css::uno::Reference< css::beans::XPropertySet> const & xColumn,
329                             SvNumberFormatter* pNFormatr,
330                             LanguageType nLanguage );
331 
332     sal_uLong GetColumnFormat( const OUString& rDBName,
333                             const OUString& rTableName,
334                             const OUString& rColNm,
335                             SvNumberFormatter* pNFormatr,
336                             LanguageType nLanguage );
337     sal_Int32 GetColumnType( const OUString& rDBName,
338                           const OUString& rTableName,
339                           const OUString& rColNm );
340 
IsInMerge() const341     bool     IsInMerge() const   { return m_bInMerge; }
342 
343     void            ExecuteFormLetter(SwWrtShell& rSh,
344                         const css::uno::Sequence< css::beans::PropertyValue>& rProperties);
345 
346     static void     InsertText(SwWrtShell& rSh,
347                         const css::uno::Sequence< css::beans::PropertyValue>& rProperties);
348 
349     /// check if a data source is open
350     bool            IsDataSourceOpen(const OUString& rDataSource,
351                                     const OUString& rTableOrQuery, bool bMergeShell);
352 
353     /// open the source while fields are updated - for the calculator only!
354     bool            OpenDataSource(const OUString& rDataSource, const OUString& rTableOrQuery);
355     sal_uInt32      GetSelectedRecordId(const OUString& rDataSource, const OUString& rTableOrQuery, sal_Int32 nCommandType = -1);
356     bool            GetColumnCnt(const OUString& rSourceName, const OUString& rTableName,
357                             const OUString& rColumnName, sal_uInt32 nAbsRecordId, LanguageType nLanguage,
358                             OUString& rResult, double* pNumber);
359     /** create and store or find an already stored connection to a data source for use
360     in SwFieldMgr and SwDBTreeList */
361     css::uno::Reference< css::sdbc::XConnection> const &
362                     RegisterConnection(OUString const& rSource);
363 
CreateDSData(const SwDBData & rData)364     void            CreateDSData(const SwDBData& rData)
365                         { FindDSData(rData, true); }
GetDSParamArray() const366     const SwDSParams_t& GetDSParamArray() const { return m_DataSourceParams; }
367 
368     /// close all data sources - after fields were updated
369     void            CloseAll(bool bIncludingMerge = true);
370 
371     bool            GetMergeColumnCnt(const OUString& rColumnName, LanguageType nLanguage,
372                                       OUString &rResult, double *pNumber);
373     bool            FillCalcWithMergeData(SvNumberFormatter *pDocFormatter,
374                                           LanguageType nLanguage, SwCalc &aCalc);
375     void            ToNextRecord(const OUString& rDataSource, const OUString& rTableOrQuery);
376 
377     sal_uInt32      GetSelectedRecordId();
378     bool            ToRecordId(sal_Int32 nSet);
379 
380     static const SwDBData& GetAddressDBName();
381 
382     static OUString GetDBField(
383                     css::uno::Reference< css::beans::XPropertySet > const & xColumnProp,
384                     const SwDBFormatData& rDBFormatData,
385                     double *pNumber = nullptr);
386 
387     static css::uno::Reference< css::sdbc::XConnection>
388             GetConnection(const OUString& rDataSource,
389                 css::uno::Reference< css::sdbc::XDataSource>& rxSource,
390                 const SwView* pView);
391 
392     static css::uno::Reference< css::sdbcx::XColumnsSupplier>
393             GetColumnSupplier(css::uno::Reference< css::sdbc::XConnection> const & xConnection,
394                                     const OUString& rTableOrQuery,
395                                     SwDBSelect eTableOrQuery = SwDBSelect::UNKNOWN);
396 
397     static css::uno::Sequence<OUString> GetExistingDatabaseNames();
398 
399     /**
400      Loads a data source from file and registers it.
401 
402      This function requires GUI interaction, as it loads the data source from
403      the filename returned by a file picker and additional settings dialog.
404      In case of success it returns the registered name, otherwise an empty string.
405      */
406     static OUString            LoadAndRegisterDataSource(weld::Window* pParent, SwDocShell* pDocShell = nullptr);
407 
408     /**
409      Loads a data source from file and registers it.
410 
411      Convenience function, which calls GetDBunoURI and has just one mandatory parameter.
412      In case of success it returns the registered name, otherwise an empty string.
413      */
414     static OUString            LoadAndRegisterDataSource(const OUString& rURI, const OUString *pDestDir);
415 
416     /// Load the embedded data source of the document and also register it.
417     void LoadAndRegisterEmbeddedDataSource(const SwDBData& rData, const SwDocShell& rDocShell);
418 
419     /// Unregister a data source.
420     static void RevokeDataSource(const OUString& rName);
421 
422     /** try to get the data source from the given connection through the XChild interface.
423         If this is not possible, the data source will be created through its name.
424         @param _xConnection
425             The connection which should support the XChild interface. (not a must)
426         @param _sDataSourceName
427             The data source name will be used to create the data source when the connection can not be used for it.
428         @return
429             The data source.
430     */
431     static css::uno::Reference< css::sdbc::XDataSource>
432             getDataSourceAsParent(const css::uno::Reference< css::sdbc::XConnection>& _xConnection,const OUString& _sDataSourceName);
433 
434     /** creates a RowSet, which must be disposed after use.
435         @param  _sDataSourceName
436             The data source name
437         @param  _sCommand
438             The command.
439         @param  _nCommandType
440             The type of the command.
441         @param  _xConnection
442             The active connection which may be <NULL/>.
443         @return
444             The new created RowSet.
445 
446     */
447     static css::uno::Reference< css::sdbc::XResultSet>
448             createCursor(const OUString& _sDataSourceName,
449                          const OUString& _sCommand,
450                          sal_Int32 _nCommandType,
451                          const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
452                          const SwView* pView);
453 
454     void setEmbeddedName(const OUString& rEmbeddedName, SwDocShell& rDocShell);
455     const OUString& getEmbeddedName() const;
456 
457     // rOwnURL should be taken using INetURLObject::GetMainURL(INetURLObject::DecodeMechanism::NONE)
458     static void StoreEmbeddedDataSource(const css::uno::Reference<css::frame::XStorable>& xStorable,
459                                         const css::uno::Reference<css::embed::XStorage>& xStorage,
460                                         const OUString& rStreamRelPath,
461                                         const OUString& rOwnURL, bool bCopyTo = false);
462 
463     SwDoc* getDoc() const;
464     /// Stop reacting to removed database registrations.
465     void releaseRevokeListener();
466 
467     /// Revoke not committed registrations in case of mail merge cancel
468     void RevokeLastRegistrations();
469 
470     /// Accept not committed registrations
471     void CommitLastRegistrations();
472 
473     /// Remove not used connections.
474     void RevokeNotUsedConnections();
475 };
476 
477 namespace sw
478 {
479 enum class DBConnURIType
480 {
481     UNKNOWN = 0,
482     ODB,
483     CALC,
484     DBASE,
485     FLAT,
486     MSJET,
487     MSACE,
488     WRITER
489 };
490 
491 DBConnURIType SW_DLLPUBLIC GetDBunoType(const INetURLObject &rURL);
492 }
493 
494 #endif
495 
496 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
497